Skip to content

Commit 2f706bc

Browse files
committedSep 23, 2014
Refactoring ready for manual update dialog. Also improves labelling of StdDev classifications and better determination of decimal places to use
1 parent 91358aa commit 2f706bc

File tree

7 files changed

+149
-74
lines changed

7 files changed

+149
-74
lines changed
 

‎python/core/symbology-ng/qgsgraduatedsymbolrendererv2.sip

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,12 +107,14 @@ class QgsGraduatedSymbolRendererV2 : QgsFeatureRendererV2
107107

108108
Mode mode() const;
109109
void setMode( Mode mode );
110+
void updateClasses( QgsVectorLayer *vlayer, Mode mode, int nclasses );
110111

111112
QString units();
112113
void setUnits( QString units, bool updateRanges=true );
113114

114115
int decimalPlaces() const;
115116
void setDecimalPlaces( int decimalPlaces, bool updateRanges=true );
117+
void calculateDecimalPlaces( bool updateRanges=true );
116118

117119
static QgsGraduatedSymbolRendererV2* createRenderer(
118120
QgsVectorLayer* vlayer,

‎python/gui/symbology-ng/qgsgraduatedsymbolrendererv2widget.sip

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,9 @@ class QgsGraduatedSymbolRendererV2Widget : QgsRendererV2Widget
4040
void rowsMoved();
4141

4242
protected:
43-
void updateUiFromRenderer();
43+
void updateUiFromRenderer( bool updateCount=true );
44+
void connectUpdateHandlers();
45+
void disconnectUpdateHandlers();
4446

4547
void updateGraduatedSymbolIcon();
4648

‎src/core/symbology-ng/qgsgraduatedsymbolrendererv2.cpp

Lines changed: 76 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -630,7 +630,7 @@ static QList<double> _calcPrettyBreaks( double minimum, double maximum, int clas
630630
} // _calcPrettyBreaks
631631

632632

633-
static QList<double> _calcStdDevBreaks( QList<double> values, int classes, QList<int> &labels )
633+
static QList<double> _calcStdDevBreaks( QList<double> values, int classes, QList<double> &labels )
634634
{
635635

636636
// C++ implementation of the standard deviation class interval algorithm
@@ -669,7 +669,7 @@ static QList<double> _calcStdDevBreaks( QList<double> values, int classes, QList
669669
QList<double> breaks = _calcPrettyBreaks(( minimum - mean ) / stdDev, ( maximum - mean ) / stdDev, classes );
670670
for ( int i = 0; i < breaks.count(); i++ )
671671
{
672-
labels.append(( int ) breaks[i] );
672+
labels.append( breaks[i] );
673673
breaks[i] = ( breaks[i] * stdDev ) + mean;
674674
}
675675

@@ -820,10 +820,31 @@ QgsGraduatedSymbolRendererV2* QgsGraduatedSymbolRendererV2::createRenderer(
820820
QString units,
821821
int decimalPlaces )
822822
{
823-
if ( classes < 1 )
824-
return NULL;
823+
QgsRangeList ranges;
824+
QgsGraduatedSymbolRendererV2* r = new QgsGraduatedSymbolRendererV2( attrName, ranges );
825+
r->setSourceSymbol( symbol->clone() );
826+
r->setSourceColorRamp( ramp->clone() );
827+
r->setInvertedColorRamp( inverted );
828+
r->setMode( mode );
829+
r->setUnits( units );
830+
r->updateClasses(vlayer,mode,classes);
831+
r->setDecimalPlaces( decimalPlaces );
832+
833+
return r;
834+
}
825835

826-
int attrNum = vlayer->fieldNameIndex( attrName );
836+
837+
void QgsGraduatedSymbolRendererV2::updateClasses( QgsVectorLayer *vlayer, Mode mode, int nclasses )
838+
{
839+
// Custom classes are not recalculated
840+
setMode(mode);
841+
if( mode == Custom ) return;
842+
843+
844+
845+
if ( nclasses < 1 ) nclasses=1;
846+
847+
int attrNum = vlayer->fieldNameIndex( mAttrName );
827848
double minimum;
828849
double maximum;
829850

@@ -832,9 +853,9 @@ QgsGraduatedSymbolRendererV2* QgsGraduatedSymbolRendererV2::createRenderer(
832853
if ( attrNum == -1 )
833854
{
834855
// try to use expression
835-
expression.reset( new QgsExpression( attrName ) );
856+
expression.reset( new QgsExpression( mAttrName ) );
836857
if ( expression->hasParserError() || !expression->prepare( vlayer->pendingFields() ) )
837-
return 0; // should have a means to report errors
858+
return; // should have a means to report errors
838859

839860
QList<double> values;
840861
QgsFeatureIterator fit = vlayer->getFeatures();
@@ -855,14 +876,14 @@ QgsGraduatedSymbolRendererV2* QgsGraduatedSymbolRendererV2::createRenderer(
855876

856877
QgsDebugMsg( QString( "min %1 // max %2" ).arg( minimum ).arg( maximum ) );
857878
QList<double> breaks;
858-
QList<int> labels;
879+
QList<double> labels;
859880
if ( mode == EqualInterval )
860881
{
861-
breaks = _calcEqualIntervalBreaks( minimum, maximum, classes );
882+
breaks = _calcEqualIntervalBreaks( minimum, maximum, nclasses );
862883
}
863884
else if ( mode == Pretty )
864885
{
865-
breaks = _calcPrettyBreaks( minimum, maximum, classes );
886+
breaks = _calcPrettyBreaks( minimum, maximum, nclasses );
866887
}
867888
else if ( mode == Quantile || mode == Jenks || mode == StdDev )
868889
{
@@ -871,7 +892,7 @@ QgsGraduatedSymbolRendererV2* QgsGraduatedSymbolRendererV2::createRenderer(
871892
QgsFeature f;
872893
QStringList lst;
873894
if ( expression.isNull() )
874-
lst.append( attrName );
895+
lst.append( mAttrName );
875896
else
876897
lst = expression->referencedColumns();
877898

@@ -888,76 +909,65 @@ QgsGraduatedSymbolRendererV2* QgsGraduatedSymbolRendererV2::createRenderer(
888909
// calculate the breaks
889910
if ( mode == Quantile )
890911
{
891-
breaks = _calcQuantileBreaks( values, classes );
912+
breaks = _calcQuantileBreaks( values, nclasses );
892913
}
893914
else if ( mode == Jenks )
894915
{
895-
breaks = _calcJenksBreaks( values, classes, minimum, maximum );
916+
breaks = _calcJenksBreaks( values, nclasses, minimum, maximum );
896917
}
897918
else if ( mode == StdDev )
898919
{
899-
breaks = _calcStdDevBreaks( values, classes, labels );
920+
breaks = _calcStdDevBreaks( values, nclasses, labels );
900921
}
901922
}
902923
else
903924
{
904925
Q_ASSERT( false );
905926
}
906927

907-
QgsRangeList ranges;
928+
908929
double lower, upper = minimum;
909930
QString label;
910-
911-
QgsGraduatedSymbolRendererV2* r = new QgsGraduatedSymbolRendererV2( attrName, ranges );
912-
r->setSourceSymbol( symbol->clone() );
913-
r->setSourceColorRamp( ramp->clone() );
914-
r->setInvertedColorRamp( inverted );
915-
r->setMode( mode );
916-
r->setUnits( units );
917-
r->setDecimalPlaces( decimalPlaces );
931+
mRanges.clear();
918932

919933
// "breaks" list contains all values at class breaks plus maximum as last break
934+
920935
int i = 0;
921936
for ( QList<double>::iterator it = breaks.begin(); it != breaks.end(); ++it, ++i )
922937
{
923938
lower = upper; // upper border from last interval
924939
upper = *it;
925940

926941
// Symbol based on range
927-
QgsSymbolV2* newSymbol = symbol->clone();
928-
double colorValue;
929-
if ( inverted ) colorValue = ( breaks.count() > 1 ? ( double )( breaks.count() - i - 1 ) / ( breaks.count() - 1 ) : 0 );
930-
else colorValue = ( breaks.count() > 1 ? ( double ) i / ( breaks.count() - 1 ) : 0 );
931-
newSymbol->setColor( ramp->color( colorValue ) ); // color from (0 / cl-1) to (cl-1 / cl-1)
932-
942+
QgsSymbolV2* newSymbol = mSourceSymbol->clone();
933943
QgsRendererRangeV2 range = QgsRendererRangeV2( lower, upper, newSymbol, "" );
934944

935945
// Label - either StdDev label or default label for a range
936946
if ( mode == StdDev )
937947
{
938948
if ( i == 0 )
939949
{
940-
label = "< " + QString::number( labels[i], 'i', 0 ) + " Std Dev";
950+
label = "< " + QString::number( labels[i], 'f', 2 ) + " Std Dev";
941951
}
942952
else if ( i == labels.count() - 1 )
943953
{
944-
label = ">= " + QString::number( labels[i-1], 'i', 0 ) + " Std Dev";
954+
label = ">= " + QString::number( labels[i-1], 'f', 2 ) + " Std Dev";
945955
}
946956
else
947957
{
948-
label = QString::number( labels[i-1], 'i', 0 ) + " Std Dev" + " - " + QString::number( labels[i], 'i', 0 ) + " Std Dev";
958+
label = QString::number( labels[i-1], 'f', 2 ) + " Std Dev" + " - " + QString::number( labels[i], 'f', 2 ) + " Std Dev";
949959
}
950960
}
951961
else
952962
{
953-
label=r->defaultRangeLabel(range);
963+
label=defaultRangeLabel(range);
954964
}
955965
range.setLabel(label);
956966

957-
r->addClass( range );
967+
addClass( range );
958968
}
969+
updateColorRamp(0,mInvertedColorRamp);
959970

960-
return r;
961971
}
962972

963973

@@ -1201,18 +1211,20 @@ void QgsGraduatedSymbolRendererV2::setSourceColorRamp( QgsVectorColorRampV2* ram
12011211
void QgsGraduatedSymbolRendererV2::updateColorRamp( QgsVectorColorRampV2 *ramp, bool inverted )
12021212
{
12031213
int i = 0;
1214+
if( ramp ) this->setSourceColorRamp( ramp );
1215+
this->setInvertedColorRamp( inverted );
1216+
12041217
foreach ( QgsRendererRangeV2 range, mRanges )
12051218
{
12061219
QgsSymbolV2* symbol = range.symbol()->clone();
12071220
double colorValue;
12081221
if ( inverted ) colorValue = ( mRanges.count() > 1 ? ( double )( mRanges.count() - i - 1 ) / ( mRanges.count() - 1 ) : 0 );
12091222
else colorValue = ( mRanges.count() > 1 ? ( double ) i / ( mRanges.count() - 1 ) : 0 );
1210-
symbol->setColor( ramp->color( colorValue ) );
1223+
symbol->setColor( mSourceColorRamp->color( colorValue ) );
12111224
updateRangeSymbol( i, symbol );
12121225
++i;
12131226
}
1214-
this->setSourceColorRamp( ramp );
1215-
this->setInvertedColorRamp( inverted );
1227+
12161228
}
12171229

12181230
void QgsGraduatedSymbolRendererV2::updateSymbols( QgsSymbolV2 *sym )
@@ -1343,6 +1355,32 @@ void QgsGraduatedSymbolRendererV2::setDecimalPlaces( int decimalPlaces, bool upd
13431355
mDecimalPlaces=decimalPlaces;
13441356
}
13451357

1358+
void QgsGraduatedSymbolRendererV2::calculateDecimalPlaces( bool updateRanges )
1359+
{
1360+
// Find the minimum size of a class
1361+
double minClassRange=0.0;
1362+
for ( QgsRangeList::iterator it = mRanges.begin(); it != mRanges.end(); ++it )
1363+
{
1364+
double range = it->upperValue()-it->lowerValue();
1365+
if( range <= 0.0 ) continue;
1366+
if( minClassRange == 0.0 || range < minClassRange ) minClassRange=range;
1367+
}
1368+
if( minClassRange <= 0.0 ) return;
1369+
1370+
// Now set the number of decimal places to ensure no more than 20% error in
1371+
// representing this range (up to 10% at upper and lower end)
1372+
1373+
int ndp=10;
1374+
double nextDpMinRange=0.0000000099;
1375+
while( ndp > 0 && nextDpMinRange < minClassRange )
1376+
{
1377+
ndp--;
1378+
nextDpMinRange *= 10.0;
1379+
}
1380+
1381+
setDecimalPlaces(ndp,updateRanges);
1382+
}
1383+
13461384
void QgsGraduatedSymbolRendererV2::moveClass( int from, int to )
13471385
{
13481386
if ( from < 0 || from >= mRanges.size() || to < 0 || to >= mRanges.size() ) return;

‎src/core/symbology-ng/qgsgraduatedsymbolrendererv2.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,12 +131,14 @@ class CORE_EXPORT QgsGraduatedSymbolRendererV2 : public QgsFeatureRendererV2
131131

132132
Mode mode() const { return mMode; }
133133
void setMode( Mode mode ) { mMode = mode; }
134+
void updateClasses( QgsVectorLayer *vlayer, Mode mode, int nclasses );
134135

135136
QString units() const { return mUnits; }
136137
void setUnits( QString units, bool updateRanges=true );
137138

138139
int decimalPlaces() const { return mDecimalPlaces; }
139140
void setDecimalPlaces( int decimalPlaces, bool updateRanges=true );
141+
void calculateDecimalPlaces( bool updateRanges=true );
140142

141143
static QgsGraduatedSymbolRendererV2* createRenderer(
142144
QgsVectorLayer* vlayer,

‎src/gui/symbology-ng/qgsgraduatedsymbolrendererv2widget.cpp

Lines changed: 58 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -401,12 +401,6 @@ QgsGraduatedSymbolRendererV2Widget::QgsGraduatedSymbolRendererV2Widget( QgsVecto
401401
cboGraduatedColorRamp->setCurrentIndex( index );
402402
}
403403

404-
mModel = new QgsGraduatedSymbolRendererV2Model( this );
405-
mModel->setRenderer( mRenderer );
406-
viewGraduated->setModel( mModel );
407-
viewGraduated->resizeColumnToContents( 0 );
408-
viewGraduated->resizeColumnToContents( 1 );
409-
viewGraduated->resizeColumnToContents( 2 );
410404

411405
viewGraduated->setStyle( new QgsGraduatedSymbolRendererV2ViewStyle( viewGraduated->style() ) );
412406

@@ -426,16 +420,11 @@ QgsGraduatedSymbolRendererV2Widget::QgsGraduatedSymbolRendererV2Widget( QgsVecto
426420
connect( btnGraduatedAdd, SIGNAL( clicked() ), this, SLOT( addClass() ) );
427421
connect( cbxLinkBoundaries, SIGNAL( toggled( bool ) ), this, SLOT( toggleBoundariesLink( bool ) ) );
428422

423+
connectUpdateHandlers();
424+
429425
// initialize from previously set renderer
430426
updateUiFromRenderer();
431427

432-
connect( spinGraduatedClasses, SIGNAL( valueChanged( int ) ) , this, SLOT( classifyGraduated() ) );
433-
connect( cboGraduatedMode, SIGNAL( currentIndexChanged( int ) ) , this, SLOT( classifyGraduated() ) );
434-
connect( cboGraduatedColorRamp, SIGNAL( currentIndexChanged( int ) ) , this, SLOT( reapplyColorRamp() ) );
435-
connect( cbxInvertedColorRamp, SIGNAL( toggled( bool ) ) , this, SLOT( reapplyColorRamp() ) );
436-
connect( spinDecimalPlaces, SIGNAL(valueChanged(int)), this, SLOT(decimalPlacesChanged()));
437-
connect( txtUnits, SIGNAL( textChanged(QString)), this, SLOT(unitsChanged(QString)));
438-
439428
// menus for data-defined rotation/size
440429
QMenu* advMenu = new QMenu;
441430

@@ -460,22 +449,48 @@ QgsFeatureRendererV2* QgsGraduatedSymbolRendererV2Widget::renderer()
460449
return mRenderer;
461450
}
462451

452+
// Connect/disconnect event handlers which trigger updating renderer
453+
454+
void QgsGraduatedSymbolRendererV2Widget::connectUpdateHandlers()
455+
{
456+
connect( spinGraduatedClasses, SIGNAL( valueChanged( int ) ) , this, SLOT( classifyGraduated() ) );
457+
connect( cboGraduatedMode, SIGNAL( currentIndexChanged( int ) ) , this, SLOT( classifyGraduated() ) );
458+
connect( cboGraduatedColorRamp, SIGNAL( currentIndexChanged( int ) ) , this, SLOT( reapplyColorRamp() ) );
459+
connect( cbxInvertedColorRamp, SIGNAL( toggled( bool ) ) , this, SLOT( reapplyColorRamp() ) );
460+
connect( spinDecimalPlaces, SIGNAL(valueChanged(int)), this, SLOT(decimalPlacesChanged()));
461+
connect( txtUnits, SIGNAL( textChanged(QString)), this, SLOT(unitsChanged(QString)));
462+
}
463+
464+
// Connect/disconnect event handlers which trigger updating renderer
465+
466+
void QgsGraduatedSymbolRendererV2Widget::disconnectUpdateHandlers()
467+
{
468+
disconnect( spinGraduatedClasses, SIGNAL( valueChanged( int ) ) , this, SLOT( classifyGraduated() ) );
469+
disconnect( cboGraduatedMode, SIGNAL( currentIndexChanged( int ) ) , this, SLOT( classifyGraduated() ) );
470+
disconnect( cboGraduatedColorRamp, SIGNAL( currentIndexChanged( int ) ) , this, SLOT( reapplyColorRamp() ) );
471+
disconnect( cbxInvertedColorRamp, SIGNAL( toggled( bool ) ) , this, SLOT( reapplyColorRamp() ) );
472+
disconnect( spinDecimalPlaces, SIGNAL(valueChanged(int)), this, SLOT(decimalPlacesChanged()));
473+
disconnect( txtUnits, SIGNAL( textChanged(QString)), this, SLOT(unitsChanged(QString)));
474+
}
463475

464-
void QgsGraduatedSymbolRendererV2Widget::updateUiFromRenderer()
476+
void QgsGraduatedSymbolRendererV2Widget::updateUiFromRenderer( bool updateCount )
465477
{
478+
disconnectUpdateHandlers();
479+
466480
updateGraduatedSymbolIcon();
467481

468482
// update UI from the graduated renderer (update combo boxes, view)
469483
if ( mRenderer->mode() < cboGraduatedMode->count() )
470484
cboGraduatedMode->setCurrentIndex( mRenderer->mode() );
471-
if ( mRenderer->ranges().count() )
485+
486+
// Only update class count if different - otherwise typing value gets very messy
487+
int nclasses=mRenderer->ranges().count();
488+
if ( nclasses && updateCount )
472489
spinGraduatedClasses->setValue( mRenderer->ranges().count() );
473490

474491
// set column
475-
disconnect( mExpressionWidget, SIGNAL( fieldChanged( QString ) ), this, SLOT( graduatedColumnChanged( QString ) ) );
476492
QString attrName = mRenderer->classAttribute();
477493
mExpressionWidget->setField( attrName );
478-
connect( mExpressionWidget, SIGNAL( fieldChanged( QString ) ), this, SLOT( graduatedColumnChanged( QString ) ) );
479494

480495
// set source symbol
481496
if ( mRenderer->sourceSymbol() )
@@ -494,6 +509,15 @@ void QgsGraduatedSymbolRendererV2Widget::updateUiFromRenderer()
494509

495510
spinDecimalPlaces->setValue( mRenderer->decimalPlaces());
496511
txtUnits->setText( mRenderer->units() );
512+
513+
mModel = new QgsGraduatedSymbolRendererV2Model( this );
514+
mModel->setRenderer( mRenderer );
515+
viewGraduated->setModel( mModel );
516+
viewGraduated->resizeColumnToContents( 0 );
517+
viewGraduated->resizeColumnToContents( 1 );
518+
viewGraduated->resizeColumnToContents( 2 );
519+
520+
connectUpdateHandlers();
497521
}
498522

499523
void QgsGraduatedSymbolRendererV2Widget::graduatedColumnChanged( QString field )
@@ -505,7 +529,7 @@ void QgsGraduatedSymbolRendererV2Widget::classifyGraduated()
505529
{
506530
QString attrName = mExpressionWidget->currentField();
507531

508-
int classes = spinGraduatedClasses->value();
532+
int nclasses = spinGraduatedClasses->value();
509533

510534
QgsVectorColorRampV2* ramp = cboGraduatedColorRamp->currentColorRamp();
511535

@@ -527,6 +551,8 @@ void QgsGraduatedSymbolRendererV2Widget::classifyGraduated()
527551
mode = QgsGraduatedSymbolRendererV2::StdDev;
528552
else if ( cboGraduatedMode->currentIndex() == 4 )
529553
mode = QgsGraduatedSymbolRendererV2::Pretty;
554+
else if ( cboGraduatedMode->currentIndex() == 5)
555+
mode = QgsGraduatedSymbolRendererV2::Custom;
530556
else // default should be quantile for now
531557
mode = QgsGraduatedSymbolRendererV2::Quantile;
532558

@@ -541,26 +567,24 @@ void QgsGraduatedSymbolRendererV2Widget::classifyGraduated()
541567

542568
// create and set new renderer
543569
QApplication::setOverrideCursor( Qt::WaitCursor );
544-
QgsGraduatedSymbolRendererV2* r = QgsGraduatedSymbolRendererV2::createRenderer(
545-
mLayer, attrName, classes, mode, mGraduatedSymbol, ramp,
546-
cbxInvertedColorRamp->isChecked(), txtUnits->text(), spinDecimalPlaces->value() );
547-
QApplication::restoreOverrideCursor();
548-
if ( !r )
570+
mRenderer->setClassAttribute(attrName);
571+
mRenderer->setMode(mode);
572+
bool updateUiCount=true;
573+
if( mode == QgsGraduatedSymbolRendererV2::Custom )
549574
{
550-
QMessageBox::critical( this, tr( "Error" ), tr( "Renderer creation has failed." ) );
551-
return;
575+
// Need to insert code for manually setting ranges
552576
}
553-
554-
r->setSizeScaleField( mRenderer->sizeScaleField() );
555-
r->setRotationField( mRenderer->rotationField() );
556-
r->setScaleMethod( mRenderer->scaleMethod() );
557-
558-
if ( mModel )
577+
else
559578
{
560-
mModel->setRenderer( r );
579+
mRenderer->updateClasses(mLayer,mode,nclasses);
580+
// PrettyBreaks and StdDev calculation don't generate exact
581+
// number of classes - leave user interface unchanged for these
582+
updateUiCount=false;
561583
}
562-
delete mRenderer;
563-
mRenderer = r;
584+
mRenderer->calculateDecimalPlaces();
585+
586+
QApplication::restoreOverrideCursor();
587+
updateUiFromRenderer( updateUiCount );
564588
}
565589

566590
void QgsGraduatedSymbolRendererV2Widget::reapplyColorRamp()

‎src/gui/symbology-ng/qgsgraduatedsymbolrendererv2widget.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,9 @@ class GUI_EXPORT QgsGraduatedSymbolRendererV2Widget : public QgsRendererV2Widget
110110
void rowsMoved();
111111

112112
protected:
113-
void updateUiFromRenderer();
113+
void updateUiFromRenderer( bool updateCount=true );
114+
void connectUpdateHandlers();
115+
void disconnectUpdateHandlers();
114116

115117
void updateGraduatedSymbolIcon();
116118

‎src/ui/qgsgraduatedsymbolrendererv2widget.ui

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,11 @@
6969
<string>Pretty Breaks</string>
7070
</property>
7171
</item>
72+
<item>
73+
<property name="text">
74+
<string>Manual Breaks</string>
75+
</property>
76+
</item>
7277
</widget>
7378
</item>
7479
<item row="5" column="0">

0 commit comments

Comments
 (0)
Please sign in to comment.