QGIS API Documentation 3.43.0-Master (c67cf405802)
qgsgraduatedsymbolrenderer.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgsgraduatedsymbolrenderer.cpp
3 ---------------------
4 begin : November 2009
5 copyright : (C) 2009 by Martin Dobias
6 email : wonder dot sk at gmail dot com
7 ***************************************************************************
8 * *
9 * This program is free software; you can redistribute it and/or modify *
10 * it under the terms of the GNU General Public License as published by *
11 * the Free Software Foundation; either version 2 of the License, or *
12 * (at your option) any later version. *
13 * *
14 ***************************************************************************/
15
16#include <QDomDocument>
17#include <QDomElement>
18
19#include <ctime>
20#include <cmath>
21
23
24#include "qgsattributes.h"
26#include "qgscolorramp.h"
27#include "qgscolorrampimpl.h"
29#include "qgsexpression.h"
30#include "qgsfeature.h"
32#include "qgspainteffect.h"
33#include "qgsproperty.h"
34#include "qgssymbol.h"
35#include "qgssymbollayer.h"
36#include "qgssymbollayerutils.h"
38#include "qgsvectorlayer.h"
39#include "qgsvectorlayerutils.h"
44#include "qgsapplication.h"
47#include "qgsmarkersymbol.h"
48#include "qgslinesymbol.h"
50
52 : QgsFeatureRenderer( QStringLiteral( "graduatedSymbol" ) )
53 , mAttrName( attrName )
54{
55 // TODO: check ranges for sanity (NULL symbols, invalid ranges)
56
57 //important - we need a deep copy of the ranges list, not a shared copy. This is required because
58 //QgsRendererRange::symbol() is marked const, and so retrieving the symbol via this method does not
59 //trigger a detachment and copy of mRanges BUT that same method CAN be used to modify a symbol in place
60 const auto constRanges = ranges;
61 for ( const QgsRendererRange &range : constRanges )
62 {
63 mRanges << range;
64 }
65
67}
68
70{
71 mRanges.clear(); // should delete all the symbols
72}
73
75{
77 auto catIt = mRanges.constBegin();
78 for ( ; catIt != mRanges.constEnd(); ++catIt )
79 {
80 if ( QgsSymbol *catSymbol = catIt->symbol() )
81 {
82 if ( catSymbol->flags().testFlag( Qgis::SymbolFlag::AffectsLabeling ) )
84 }
85 }
86
87 return res;
88}
89
91{
92 for ( const QgsRendererRange &range : mRanges )
93 {
94 if ( range.lowerValue() <= value && range.upperValue() >= value )
95 {
96 if ( range.renderState() || mCounting )
97 return &range;
98 else
99 return nullptr;
100 }
101 }
102
103 // second chance -- use a bit of double tolerance to avoid floating point equality fuzziness
104 // if a value falls just outside of a range, but within acceptable double precision tolerance
105 // then we accept it anyway
106 for ( const QgsRendererRange &range : mRanges )
107 {
108 if ( qgsDoubleNear( range.lowerValue(), value ) || qgsDoubleNear( range.upperValue(), value ) )
109 {
110 if ( range.renderState() || mCounting )
111 return &range;
112 else
113 return nullptr;
114 }
115 }
116 // the value is out of the range: return NULL instead of symbol
117 return nullptr;
118}
119
121{
122 if ( const QgsRendererRange *range = rangeForValue( value ) )
123 return range->symbol();
124 return nullptr;
125}
126
128{
129 if ( const QgsRendererRange *matchingRange = rangeForValue( value ) )
130 {
131 for ( const QgsRendererRange &range : mRanges )
132 {
133 if ( matchingRange == &range )
134 return range.uuid();
135 }
136 }
137 return QString();
138}
139
141{
142 return originalSymbolForFeature( feature, context );
143}
144
145QVariant QgsGraduatedSymbolRenderer::valueForFeature( const QgsFeature &feature, QgsRenderContext &context ) const
146{
147 QgsAttributes attrs = feature.attributes();
148 QVariant value;
149 if ( mExpression )
150 {
151 value = mExpression->evaluate( &context.expressionContext() );
152 }
153 else
154 {
155 value = attrs.value( mAttrNum );
156 }
157
158 return value;
159}
160
162{
163 QVariant value = valueForFeature( feature, context );
164
165 // Null values should not be categorized
166 if ( QgsVariantUtils::isNull( value ) )
167 return nullptr;
168
169 // find the right category
170 return symbolForValue( value.toDouble() );
171}
172
174{
175 QgsFeatureRenderer::startRender( context, fields );
176
177 mCounting = context.rendererScale() == 0.0;
178
179 // find out classification attribute index from name
180 mAttrNum = fields.lookupField( mAttrName );
181
182 if ( mAttrNum == -1 )
183 {
184 mExpression.reset( new QgsExpression( mAttrName ) );
185 mExpression->prepare( &context.expressionContext() );
186 }
187
188 for ( const QgsRendererRange &range : std::as_const( mRanges ) )
189 {
190 if ( !range.symbol() )
191 continue;
192
193 range.symbol()->startRender( context, fields );
194 }
195}
196
198{
200
201 for ( const QgsRendererRange &range : std::as_const( mRanges ) )
202 {
203 if ( !range.symbol() )
204 continue;
205
206 range.symbol()->stopRender( context );
207 }
208}
209
211{
212 QSet<QString> attributes;
213
214 // mAttrName can contain either attribute name or an expression.
215 // Sometimes it is not possible to distinguish between those two,
216 // e.g. "a - b" can be both a valid attribute name or expression.
217 // Since we do not have access to fields here, try both options.
218 attributes << mAttrName;
219
220 QgsExpression testExpr( mAttrName );
221 if ( !testExpr.hasParserError() )
222 attributes.unite( testExpr.referencedColumns() );
223
224 QgsRangeList::const_iterator range_it = mRanges.constBegin();
225 for ( ; range_it != mRanges.constEnd(); ++range_it )
226 {
227 QgsSymbol *symbol = range_it->symbol();
228 if ( symbol )
229 {
230 attributes.unite( symbol->usedAttributes( context ) );
231 }
232 }
233 return attributes;
234}
235
237{
238 QgsExpression testExpr( mAttrName );
239 if ( !testExpr.hasParserError() )
240 {
241 QgsExpressionContext context;
242 context.appendScopes( QgsExpressionContextUtils::globalProjectLayerScopes( nullptr ) ); // unfortunately no layer access available!
243 testExpr.prepare( &context );
244 return testExpr.needsGeometry();
245 }
246 return false;
247}
248
250{
251 if ( rangeIndex < 0 || rangeIndex >= mRanges.size() )
252 return false;
253 mRanges[rangeIndex].setSymbol( symbol );
254 return true;
255}
256
257bool QgsGraduatedSymbolRenderer::updateRangeLabel( int rangeIndex, const QString &label )
258{
259 if ( rangeIndex < 0 || rangeIndex >= mRanges.size() )
260 return false;
261 mRanges[rangeIndex].setLabel( label );
262 return true;
263}
264
265bool QgsGraduatedSymbolRenderer::updateRangeUpperValue( int rangeIndex, double value )
266{
267 if ( rangeIndex < 0 || rangeIndex >= mRanges.size() )
268 return false;
269 QgsRendererRange &range = mRanges[rangeIndex];
271 if ( rangeIndex == 0 )
273 else if ( rangeIndex == mRanges.count() )
275
276 bool isDefaultLabel = mClassificationMethod->labelForRange( range, pos ) == range.label();
277 range.setUpperValue( value );
278 if ( isDefaultLabel )
279 range.setLabel( mClassificationMethod->labelForRange( range, pos ) );
280
281 return true;
282}
283
284bool QgsGraduatedSymbolRenderer::updateRangeLowerValue( int rangeIndex, double value )
285{
286 if ( rangeIndex < 0 || rangeIndex >= mRanges.size() )
287 return false;
288
289 QgsRendererRange &range = mRanges[rangeIndex];
291 if ( rangeIndex == 0 )
293 else if ( rangeIndex == mRanges.count() )
295
296 bool isDefaultLabel = mClassificationMethod->labelForRange( range, pos ) == range.label();
297 range.setLowerValue( value );
298 if ( isDefaultLabel )
299 range.setLabel( mClassificationMethod->labelForRange( range, pos ) );
300
301 return true;
302}
303
305{
306 if ( rangeIndex < 0 || rangeIndex >= mRanges.size() )
307 return false;
308 mRanges[rangeIndex].setRenderState( value );
309 return true;
310}
311
313{
314 QString s = QStringLiteral( "GRADUATED: attr %1\n" ).arg( mAttrName );
315 for ( int i = 0; i < mRanges.count(); i++ )
316 s += mRanges[i].dump();
317 return s;
318}
319
337
338void QgsGraduatedSymbolRenderer::toSld( QDomDocument &doc, QDomElement &element, const QVariantMap &props ) const
339{
340 QVariantMap newProps = props;
341 newProps[ QStringLiteral( "attribute" )] = mAttrName;
342 newProps[ QStringLiteral( "method" )] = graduatedMethodStr( mGraduatedMethod );
343
344 // create a Rule for each range
345 bool first = true;
346 for ( QgsRangeList::const_iterator it = mRanges.constBegin(); it != mRanges.constEnd(); ++it )
347 {
348 it->toSld( doc, element, newProps, first );
349 first = false;
350 }
351}
352
354{
355 Q_UNUSED( context )
356 QgsSymbolList lst;
357 lst.reserve( mRanges.count() );
358 for ( const QgsRendererRange &range : std::as_const( mRanges ) )
359 {
360 lst.append( range.symbol() );
361 }
362 return lst;
363}
364
366{
367 for ( const QgsRendererRange &range : std::as_const( mRanges ) )
368 {
369 QgsStyleSymbolEntity entity( range.symbol() );
370 if ( !visitor->visit( QgsStyleEntityVisitorInterface::StyleLeaf( &entity, QStringLiteral( "%1 - %2" ).arg( range.lowerValue() ).arg( range.upperValue() ), range.label() ) ) )
371 return false;
372 }
373
374 if ( mSourceColorRamp )
375 {
377 if ( !visitor->visit( QgsStyleEntityVisitorInterface::StyleLeaf( &entity ) ) )
378 return false;
379 }
380
381 return true;
382}
383
384void QgsGraduatedSymbolRenderer::makeBreaksSymmetric( QList<double> &breaks, double symmetryPoint, bool astride )
385{
387}
388
389QList<double> QgsGraduatedSymbolRenderer::calcEqualIntervalBreaks( double minimum, double maximum, int classes, bool useSymmetricMode, double symmetryPoint, bool astride )
390{
393 QList<QgsClassificationRange> _classes = method.classes( minimum, maximum, classes );
395}
396
399 QgsVectorLayer *vlayer,
400 const QString &attrName,
401 int classes,
402 Mode mode,
403 QgsSymbol *symbol,
404 QgsColorRamp *ramp,
405 const QgsRendererRangeLabelFormat &labelFormat,
406 bool useSymmetricMode,
407 double symmetryPoint,
408 const QStringList &listForCboPrettyBreaks,
409 bool astride
410)
411{
412 Q_UNUSED( listForCboPrettyBreaks )
413
415 auto r = std::make_unique< QgsGraduatedSymbolRenderer >( attrName, ranges );
416 r->setSourceSymbol( symbol->clone() );
417 r->setSourceColorRamp( ramp->clone() );
418
419 QString methodId = methodIdFromMode( mode );
420 std::unique_ptr< QgsClassificationMethod > method = QgsApplication::classificationMethodRegistry()->method( methodId );
421
422 if ( method )
423 {
424 method->setSymmetricMode( useSymmetricMode, symmetryPoint, astride );
425 method->setLabelFormat( labelFormat.format() );
426 method->setLabelTrimTrailingZeroes( labelFormat.trimTrailingZeroes() );
427 method->setLabelPrecision( labelFormat.precision() );
428 }
429 r->setClassificationMethod( method.release() );
430
431 QString error;
432 r->updateClasses( vlayer, classes, error );
433 ( void )error;
434
435 return r.release();
436}
438
440 bool useSymmetricMode, double symmetryPoint, bool astride )
441{
442 if ( mAttrName.isEmpty() )
443 return;
444
445 QString methodId = methodIdFromMode( mode );
446 std::unique_ptr< QgsClassificationMethod > method = QgsApplication::classificationMethodRegistry()->method( methodId );
447 method->setSymmetricMode( useSymmetricMode, symmetryPoint, astride );
448 setClassificationMethod( method.release() );
449
450 QString error;
451 updateClasses( vlayer, nclasses, error );
452 ( void )error;
453}
454
455void QgsGraduatedSymbolRenderer::updateClasses( const QgsVectorLayer *vl, int nclasses, QString &error )
456{
457 Q_UNUSED( error )
459 return;
460
461 QList<QgsClassificationRange> classes = mClassificationMethod->classesV2( vl, mAttrName, nclasses, error );
462
464
465 for ( QList<QgsClassificationRange>::iterator it = classes.begin(); it != classes.end(); ++it )
466 {
468 addClass( QgsRendererRange( *it, newSymbol ) );
469 }
470 updateColorRamp( nullptr );
471}
472
479
481{
482 QDomElement symbolsElem = element.firstChildElement( QStringLiteral( "symbols" ) );
483 if ( symbolsElem.isNull() )
484 return nullptr;
485
486 QDomElement rangesElem = element.firstChildElement( QStringLiteral( "ranges" ) );
487 if ( rangesElem.isNull() )
488 return nullptr;
489
490 QgsSymbolMap symbolMap = QgsSymbolLayerUtils::loadSymbols( symbolsElem, context );
492
493 QDomElement rangeElem = rangesElem.firstChildElement();
494 int i = 0;
495 QSet<QString> usedUuids;
496 while ( !rangeElem.isNull() )
497 {
498 if ( rangeElem.tagName() == QLatin1String( "range" ) )
499 {
500 double lowerValue = rangeElem.attribute( QStringLiteral( "lower" ) ).toDouble();
501 double upperValue = rangeElem.attribute( QStringLiteral( "upper" ) ).toDouble();
502 QString symbolName = rangeElem.attribute( QStringLiteral( "symbol" ) );
503 QString label = rangeElem.attribute( QStringLiteral( "label" ) );
504 bool render = rangeElem.attribute( QStringLiteral( "render" ), QStringLiteral( "true" ) ) != QLatin1String( "false" );
505 QString uuid = rangeElem.attribute( QStringLiteral( "uuid" ), QString::number( i++ ) );
506 while ( usedUuids.contains( uuid ) )
507 {
508 uuid = QUuid::createUuid().toString();
509 }
510 if ( symbolMap.contains( symbolName ) )
511 {
512 QgsSymbol *symbol = symbolMap.take( symbolName );
513 ranges.append( QgsRendererRange( lowerValue, upperValue, symbol, label, render, uuid ) );
514 usedUuids << uuid;
515 }
516 }
517 rangeElem = rangeElem.nextSiblingElement();
518 }
519
520 QString attrName = element.attribute( QStringLiteral( "attr" ) );
521
522 auto r = std::make_unique< QgsGraduatedSymbolRenderer >( attrName, ranges );
523
524 QString attrMethod = element.attribute( QStringLiteral( "graduatedMethod" ) );
525 if ( !attrMethod.isEmpty() )
526 {
528 r->setGraduatedMethod( Qgis::GraduatedMethod::Color );
529 else if ( attrMethod == graduatedMethodStr( Qgis::GraduatedMethod::Size ) )
530 r->setGraduatedMethod( Qgis::GraduatedMethod::Size );
531 }
532
533
534 // delete symbols if there are any more
536
537 // try to load source symbol (optional)
538 QDomElement sourceSymbolElem = element.firstChildElement( QStringLiteral( "source-symbol" ) );
539 if ( !sourceSymbolElem.isNull() )
540 {
541 QgsSymbolMap sourceSymbolMap = QgsSymbolLayerUtils::loadSymbols( sourceSymbolElem, context );
542 if ( sourceSymbolMap.contains( QStringLiteral( "0" ) ) )
543 {
544 r->setSourceSymbol( sourceSymbolMap.take( QStringLiteral( "0" ) ) );
545 }
546 QgsSymbolLayerUtils::clearSymbolMap( sourceSymbolMap );
547 }
548
549 // try to load color ramp (optional)
550 QDomElement sourceColorRampElem = element.firstChildElement( QStringLiteral( "colorramp" ) );
551 if ( !sourceColorRampElem.isNull() && sourceColorRampElem.attribute( QStringLiteral( "name" ) ) == QLatin1String( "[source]" ) )
552 {
553 r->setSourceColorRamp( QgsSymbolLayerUtils::loadColorRamp( sourceColorRampElem ).release() );
554 }
555
556 // try to load mode
557
558 QDomElement modeElem = element.firstChildElement( QStringLiteral( "mode" ) ); // old format, backward compatibility
559 QDomElement methodElem = element.firstChildElement( QStringLiteral( "classificationMethod" ) );
560 std::unique_ptr< QgsClassificationMethod > method;
561
562 // TODO QGIS 4 Remove
563 // backward compatibility for QGIS project < 3.10
564 if ( !modeElem.isNull() )
565 {
566 QString modeString = modeElem.attribute( QStringLiteral( "name" ) );
567 QString methodId;
568 // the strings saved in the project does not match with the old Mode enum
569 if ( modeString == QLatin1String( "equal" ) )
570 methodId = QStringLiteral( "EqualInterval" );
571 else if ( modeString == QLatin1String( "quantile" ) )
572 methodId = QStringLiteral( "Quantile" );
573 else if ( modeString == QLatin1String( "jenks" ) )
574 methodId = QStringLiteral( "Jenks" );
575 else if ( modeString == QLatin1String( "stddev" ) )
576 methodId = QStringLiteral( "StdDev" );
577 else if ( modeString == QLatin1String( "pretty" ) )
578 methodId = QStringLiteral( "Pretty" );
579
581
582 // symmetric mode
583 QDomElement symmetricModeElem = element.firstChildElement( QStringLiteral( "symmetricMode" ) );
584 if ( !symmetricModeElem.isNull() )
585 {
586 // symmetry
587 QString symmetricEnabled = symmetricModeElem.attribute( QStringLiteral( "enabled" ) );
588 QString symmetricPointString = symmetricModeElem.attribute( QStringLiteral( "symmetryPoint" ) );
589 QString astrideEnabled = symmetricModeElem.attribute( QStringLiteral( "astride" ) );
590 method->setSymmetricMode( symmetricEnabled == QLatin1String( "true" ), symmetricPointString.toDouble(), astrideEnabled == QLatin1String( "true" ) );
591 }
592 QDomElement labelFormatElem = element.firstChildElement( QStringLiteral( "labelformat" ) );
593 if ( !labelFormatElem.isNull() )
594 {
595 // label format
596 QString format = labelFormatElem.attribute( QStringLiteral( "format" ), "%1" + QStringLiteral( " - " ) + "%2" );
597 int precision = labelFormatElem.attribute( QStringLiteral( "decimalplaces" ), QStringLiteral( "4" ) ).toInt();
598 bool trimTrailingZeroes = labelFormatElem.attribute( QStringLiteral( "trimtrailingzeroes" ), QStringLiteral( "false" ) ) == QLatin1String( "true" );
599 method->setLabelFormat( format );
600 method->setLabelPrecision( precision );
601 method->setLabelTrimTrailingZeroes( trimTrailingZeroes );
602 }
603 // End of backward compatibility
604 }
605 else
606 {
607 // QGIS project 3.10+
608 method = QgsClassificationMethod::create( methodElem, context );
609 }
610
611 // apply the method
612 r->setClassificationMethod( method.release() );
613
614 QDomElement rotationElem = element.firstChildElement( QStringLiteral( "rotation" ) );
615 if ( !rotationElem.isNull() && !rotationElem.attribute( QStringLiteral( "field" ) ).isEmpty() )
616 {
617 for ( const QgsRendererRange &range : std::as_const( r->mRanges ) )
618 {
619 convertSymbolRotation( range.symbol(), rotationElem.attribute( QStringLiteral( "field" ) ) );
620 }
621 if ( r->mSourceSymbol )
622 {
623 convertSymbolRotation( r->mSourceSymbol.get(), rotationElem.attribute( QStringLiteral( "field" ) ) );
624 }
625 }
626 QDomElement sizeScaleElem = element.firstChildElement( QStringLiteral( "sizescale" ) );
627 if ( !sizeScaleElem.isNull() && !sizeScaleElem.attribute( QStringLiteral( "field" ) ).isEmpty() )
628 {
629 for ( const QgsRendererRange &range : std::as_const( r->mRanges ) )
630 {
631 convertSymbolSizeScale( range.symbol(),
632 QgsSymbolLayerUtils::decodeScaleMethod( sizeScaleElem.attribute( QStringLiteral( "scalemethod" ) ) ),
633 sizeScaleElem.attribute( QStringLiteral( "field" ) ) );
634 }
635 if ( r->mSourceSymbol && r->mSourceSymbol->type() == Qgis::SymbolType::Marker )
636 {
637 convertSymbolSizeScale( r->mSourceSymbol.get(),
638 QgsSymbolLayerUtils::decodeScaleMethod( sizeScaleElem.attribute( QStringLiteral( "scalemethod" ) ) ),
639 sizeScaleElem.attribute( QStringLiteral( "field" ) ) );
640 }
641 }
642
643 QDomElement ddsLegendSizeElem = element.firstChildElement( QStringLiteral( "data-defined-size-legend" ) );
644 if ( !ddsLegendSizeElem.isNull() )
645 {
646 r->mDataDefinedSizeLegend.reset( QgsDataDefinedSizeLegend::readXml( ddsLegendSizeElem, context ) );
647 }
648// TODO: symbol levels
649 return r.release();
650}
651
652QDomElement QgsGraduatedSymbolRenderer::save( QDomDocument &doc, const QgsReadWriteContext &context )
653{
654 QDomElement rendererElem = doc.createElement( RENDERER_TAG_NAME );
655 rendererElem.setAttribute( QStringLiteral( "type" ), QStringLiteral( "graduatedSymbol" ) );
656 rendererElem.setAttribute( QStringLiteral( "attr" ), mAttrName );
657 rendererElem.setAttribute( QStringLiteral( "graduatedMethod" ), graduatedMethodStr( mGraduatedMethod ) );
658
659 // ranges
660 int i = 0;
662 QDomElement rangesElem = doc.createElement( QStringLiteral( "ranges" ) );
663 QgsRangeList::const_iterator it = mRanges.constBegin();
664 for ( ; it != mRanges.constEnd(); ++it )
665 {
666 const QgsRendererRange &range = *it;
667 QString symbolName = QString::number( i );
668 symbols.insert( symbolName, range.symbol() );
669
670 QDomElement rangeElem = doc.createElement( QStringLiteral( "range" ) );
671 rangeElem.setAttribute( QStringLiteral( "lower" ), QString::number( range.lowerValue(), 'f', 15 ) );
672 rangeElem.setAttribute( QStringLiteral( "upper" ), QString::number( range.upperValue(), 'f', 15 ) );
673 rangeElem.setAttribute( QStringLiteral( "symbol" ), symbolName );
674 rangeElem.setAttribute( QStringLiteral( "label" ), range.label() );
675 rangeElem.setAttribute( QStringLiteral( "render" ), range.renderState() ? QStringLiteral( "true" ) : QStringLiteral( "false" ) );
676 rangeElem.setAttribute( QStringLiteral( "uuid" ), range.uuid() );
677 rangesElem.appendChild( rangeElem );
678 i++;
679 }
680
681 rendererElem.appendChild( rangesElem );
682
683 // save symbols
684 QDomElement symbolsElem = QgsSymbolLayerUtils::saveSymbols( symbols, QStringLiteral( "symbols" ), doc, context );
685 rendererElem.appendChild( symbolsElem );
686
687 // save source symbol
688 if ( mSourceSymbol )
689 {
690 QgsSymbolMap sourceSymbols;
691 sourceSymbols.insert( QStringLiteral( "0" ), mSourceSymbol.get() );
692 QDomElement sourceSymbolElem = QgsSymbolLayerUtils::saveSymbols( sourceSymbols, QStringLiteral( "source-symbol" ), doc, context );
693 rendererElem.appendChild( sourceSymbolElem );
694 }
695
696 // save source color ramp
697 if ( mSourceColorRamp )
698 {
699 QDomElement colorRampElem = QgsSymbolLayerUtils::saveColorRamp( QStringLiteral( "[source]" ), mSourceColorRamp.get(), doc );
700 rendererElem.appendChild( colorRampElem );
701 }
702
703 // save classification method
704 QDomElement classificationMethodElem = mClassificationMethod->save( doc, context );
705 rendererElem.appendChild( classificationMethodElem );
706
707 QDomElement rotationElem = doc.createElement( QStringLiteral( "rotation" ) );
708 rendererElem.appendChild( rotationElem );
709
710 QDomElement sizeScaleElem = doc.createElement( QStringLiteral( "sizescale" ) );
711 rendererElem.appendChild( sizeScaleElem );
712
714 {
715 QDomElement ddsLegendElem = doc.createElement( QStringLiteral( "data-defined-size-legend" ) );
716 mDataDefinedSizeLegend->writeXml( ddsLegendElem, context );
717 rendererElem.appendChild( ddsLegendElem );
718 }
719
720 saveRendererData( doc, rendererElem, context );
721
722 return rendererElem;
723}
724
725QgsLegendSymbolList QgsGraduatedSymbolRenderer::baseLegendSymbolItems() const
726{
728 lst.reserve( mRanges.size() );
729 for ( const QgsRendererRange &range : mRanges )
730 {
731 lst << QgsLegendSymbolItem( range.symbol(), range.label(), range.uuid(), true );
732 }
733 return lst;
734}
735
737QString QgsGraduatedSymbolRenderer::methodIdFromMode( QgsGraduatedSymbolRenderer::Mode mode )
738{
739 switch ( mode )
740 {
741 case EqualInterval:
742 return QStringLiteral( "EqualInterval" );
743 case Quantile:
744 return QStringLiteral( "Quantile" );
745 case Jenks:
746 return QStringLiteral( "Jenks" );
747 case StdDev:
748 return QStringLiteral( "StdDev" );
749 case Pretty:
750 return QStringLiteral( "Pretty" );
751 case Custom:
752 return QString();
753 }
754 return QString();
755}
756
757QgsGraduatedSymbolRenderer::Mode QgsGraduatedSymbolRenderer::modeFromMethodId( const QString &methodId )
758{
759 if ( methodId == QLatin1String( "EqualInterval" ) )
760 return EqualInterval;
761 if ( methodId == QLatin1String( "Quantile" ) )
762 return Quantile;
763 if ( methodId == QLatin1String( "Jenks" ) )
764 return Jenks;
765 if ( methodId == QLatin1String( "StdDev" ) )
766 return StdDev;
767 if ( methodId == QLatin1String( "Pretty" ) )
768 return Pretty;
769 else
770 return Custom;
771}
773
775{
777 {
778 // check that all symbols that have the same size expression
779 QgsProperty ddSize;
780 for ( const QgsRendererRange &range : mRanges )
781 {
782 const QgsMarkerSymbol *symbol = static_cast<const QgsMarkerSymbol *>( range.symbol() );
783 if ( ddSize )
784 {
785 QgsProperty sSize( symbol->dataDefinedSize() );
786 if ( sSize && sSize != ddSize )
787 {
788 // no common size expression
789 return baseLegendSymbolItems();
790 }
791 }
792 else
793 {
794 ddSize = symbol->dataDefinedSize();
795 }
796 }
797
798 if ( ddSize && ddSize.isActive() )
799 {
801
803 ddSizeLegend.updateFromSymbolAndProperty( static_cast<const QgsMarkerSymbol *>( mSourceSymbol.get() ), ddSize );
804 lst += ddSizeLegend.legendSymbolList();
805
806 lst += baseLegendSymbolItems();
807 return lst;
808 }
809 }
810
811 return baseLegendSymbolItems();
812}
813
814QSet< QString > QgsGraduatedSymbolRenderer::legendKeysForFeature( const QgsFeature &feature, QgsRenderContext &context ) const
815{
816 QVariant value = valueForFeature( feature, context );
817
818 // Null values should not be categorized
819 if ( QgsVariantUtils::isNull( value ) )
820 return QSet< QString >();
821
822 // find the right category
823 QString key = legendKeyForValue( value.toDouble() );
824 if ( !key.isNull() )
825 return QSet< QString >() << key;
826 else
827 return QSet< QString >();
828}
829
830QString QgsGraduatedSymbolRenderer::legendKeyToExpression( const QString &key, QgsVectorLayer *layer, bool &ok ) const
831{
832 ok = false;
833 int i = 0;
834 for ( i = 0; i < mRanges.size(); i++ )
835 {
836 if ( mRanges[i].uuid() == key )
837 {
838 ok = true;
839 break;
840 }
841 }
842
843 if ( !ok )
844 {
845 ok = false;
846 return QString();
847 }
848
849 const QString attributeComponent = QgsExpression::quoteFieldExpression( mAttrName, layer );
850 const QgsRendererRange &range = mRanges[i];
851
852 return QStringLiteral( "(%1 >= %2) AND (%1 <= %3)" ).arg( attributeComponent, QgsExpression::quotedValue( range.lowerValue(), QMetaType::Type::Double ),
853 QgsExpression::quotedValue( range.upperValue(), QMetaType::Type::Double ) );
854}
855
860
862{
863 return mSourceSymbol.get();
864}
865
870
875
880
882{
883 if ( ramp == mSourceColorRamp.get() )
884 return;
885
886 mSourceColorRamp.reset( ramp );
887}
888
890{
891 double min = std::numeric_limits<double>::max();
892 for ( int i = 0; i < mRanges.count(); i++ )
893 {
894 double sz = 0;
895 if ( mRanges[i].symbol()->type() == Qgis::SymbolType::Marker )
896 sz = static_cast< QgsMarkerSymbol * >( mRanges[i].symbol() )->size();
897 else if ( mRanges[i].symbol()->type() == Qgis::SymbolType::Line )
898 sz = static_cast< QgsLineSymbol * >( mRanges[i].symbol() )->width();
899 min = std::min( sz, min );
900 }
901 return min;
902}
903
905{
906 double max = std::numeric_limits<double>::min();
907 for ( int i = 0; i < mRanges.count(); i++ )
908 {
909 double sz = 0;
910 if ( mRanges[i].symbol()->type() == Qgis::SymbolType::Marker )
911 sz = static_cast< QgsMarkerSymbol * >( mRanges[i].symbol() )->size();
912 else if ( mRanges[i].symbol()->type() == Qgis::SymbolType::Line )
913 sz = static_cast< QgsLineSymbol * >( mRanges[i].symbol() )->width();
914 max = std::max( sz, max );
915 }
916 return max;
917}
918
919void QgsGraduatedSymbolRenderer::setSymbolSizes( double minSize, double maxSize )
920{
921 for ( int i = 0; i < mRanges.count(); i++ )
922 {
923 std::unique_ptr<QgsSymbol> symbol( mRanges.at( i ).symbol() ? mRanges.at( i ).symbol()->clone() : nullptr );
924 const double size = mRanges.count() > 1
925 ? minSize + i * ( maxSize - minSize ) / ( mRanges.count() - 1 )
926 : .5 * ( maxSize + minSize );
927 if ( symbol->type() == Qgis::SymbolType::Marker )
928 static_cast< QgsMarkerSymbol * >( symbol.get() )->setSize( size );
929 if ( symbol->type() == Qgis::SymbolType::Line )
930 static_cast< QgsLineSymbol * >( symbol.get() )->setWidth( size );
931 updateRangeSymbol( i, symbol.release() );
932 }
933}
934
936{
937 int i = 0;
938 if ( ramp )
939 {
940 setSourceColorRamp( ramp );
941 }
942
943 if ( mSourceColorRamp )
944 {
945 for ( const QgsRendererRange &range : std::as_const( mRanges ) )
946 {
947 QgsSymbol *symbol = range.symbol() ? range.symbol()->clone() : nullptr;
948 if ( symbol )
949 {
950 double colorValue;
951 colorValue = ( mRanges.count() > 1 ? static_cast< double >( i ) / ( mRanges.count() - 1 ) : 0 );
952 symbol->setColor( mSourceColorRamp->color( colorValue ) );
953 }
954 updateRangeSymbol( i, symbol );
955 ++i;
956 }
957 }
958
959}
960
962{
963 if ( !sym )
964 return;
965
966 int i = 0;
967 for ( const QgsRendererRange &range : std::as_const( mRanges ) )
968 {
969 std::unique_ptr<QgsSymbol> symbol( sym->clone() );
970 switch ( mGraduatedMethod )
971 {
973 {
974 symbol->setColor( range.symbol()->color() );
975 break;
976 }
978 {
979 if ( symbol->type() == Qgis::SymbolType::Marker )
980 static_cast<QgsMarkerSymbol *>( symbol.get() )->setSize(
981 static_cast<QgsMarkerSymbol *>( range.symbol() )->size() );
982 else if ( symbol->type() == Qgis::SymbolType::Line )
983 static_cast<QgsLineSymbol *>( symbol.get() )->setWidth(
984 static_cast<QgsLineSymbol *>( range.symbol() )->width() );
985 break;
986 }
987 }
988 updateRangeSymbol( i, symbol.release() );
989 ++i;
990 }
991 setSourceSymbol( sym->clone() );
992}
993
995{
996 return true;
997}
998
1000{
1001 for ( const QgsRendererRange &range : std::as_const( mRanges ) )
1002 {
1003 if ( range.uuid() == key )
1004 {
1005 return range.renderState();
1006 }
1007 }
1008 return true;
1009}
1010
1011void QgsGraduatedSymbolRenderer::checkLegendSymbolItem( const QString &key, bool state )
1012{
1013 for ( int i = 0; i < mRanges.size(); i++ )
1014 {
1015 if ( mRanges[i].uuid() == key )
1016 {
1017 updateRangeRenderState( i, state );
1018 break;
1019 }
1020 }
1021}
1022
1024{
1025 bool ok = false;
1026 int i = 0;
1027 for ( i = 0; i < mRanges.size(); i++ )
1028 {
1029 if ( mRanges[i].uuid() == key )
1030 {
1031 ok = true;
1032 break;
1033 }
1034 }
1035
1036 if ( ok )
1037 updateRangeSymbol( i, symbol );
1038 else
1039 delete symbol;
1040}
1041
1043{
1044 QgsSymbol *newSymbol = symbol->clone();
1045 QString label = QStringLiteral( "0.0 - 0.0" );
1046 mRanges.insert( 0, QgsRendererRange( 0.0, 0.0, newSymbol, label ) );
1047}
1048
1049void QgsGraduatedSymbolRenderer::addClass( double lower, double upper )
1050{
1051 QgsSymbol *newSymbol = mSourceSymbol->clone();
1052 QString label = mClassificationMethod->labelForRange( lower, upper );
1053 mRanges.append( QgsRendererRange( lower, upper, newSymbol, label ) );
1054}
1055
1056void QgsGraduatedSymbolRenderer::addBreak( double breakValue, bool updateSymbols )
1057{
1058 QMutableListIterator< QgsRendererRange > it( mRanges );
1059 while ( it.hasNext() )
1060 {
1061 QgsRendererRange range = it.next();
1062 if ( range.lowerValue() < breakValue && range.upperValue() > breakValue )
1063 {
1065 newRange.setLowerValue( breakValue );
1066 newRange.setUpperValue( range.upperValue() );
1067 newRange.setLabel( mClassificationMethod->labelForRange( newRange ) );
1068 newRange.setSymbol( mSourceSymbol->clone() );
1069
1070 //update old range
1071 bool isDefaultLabel = range.label() == mClassificationMethod->labelForRange( range );
1072 range.setUpperValue( breakValue );
1073 if ( isDefaultLabel )
1074 range.setLabel( mClassificationMethod->labelForRange( range.lowerValue(), breakValue ) );
1075 it.setValue( range );
1076
1077 it.insert( newRange );
1078 break;
1079 }
1080 }
1081
1082 if ( updateSymbols )
1083 {
1084 switch ( mGraduatedMethod )
1085 {
1088 break;
1091 break;
1092 }
1093 }
1094}
1095
1097{
1098 mRanges.append( range );
1099}
1100
1102{
1103 mRanges.removeAt( idx );
1104}
1105
1110
1113{
1114 mClassificationMethod->setLabelFormat( labelFormat.format() );
1115 mClassificationMethod->setLabelPrecision( labelFormat.precision() );
1116 mClassificationMethod->setLabelTrimTrailingZeroes( labelFormat.trimTrailingZeroes() );
1117
1118 if ( updateRanges )
1119 {
1121 }
1122}
1124
1126{
1127 for ( int i = 0; i < mRanges.count(); i++ )
1128 {
1130 if ( i == 0 )
1132 else if ( i == mRanges.count() - 1 )
1134 mRanges[i].setLabel( mClassificationMethod->labelForRange( mRanges[i], pos ) );
1135 }
1136}
1137
1139{
1140 // Find the minimum size of a class
1141 double minClassRange = 0.0;
1142 for ( const QgsRendererRange &rendererRange : std::as_const( mRanges ) )
1143 {
1144 double range = rendererRange.upperValue() - rendererRange.lowerValue();
1145 if ( range <= 0.0 )
1146 continue;
1147 if ( minClassRange == 0.0 || range < minClassRange )
1148 minClassRange = range;
1149 }
1150 if ( minClassRange <= 0.0 )
1151 return;
1152
1153 // Now set the number of decimal places to ensure no more than 20% error in
1154 // representing this range (up to 10% at upper and lower end)
1155
1156 int ndp = 10;
1157 double nextDpMinRange = 0.0000000099;
1158 while ( ndp > 0 && nextDpMinRange < minClassRange )
1159 {
1160 ndp--;
1161 nextDpMinRange *= 10.0;
1162 }
1163 mClassificationMethod->setLabelPrecision( ndp );
1164 if ( updateRanges )
1166}
1167
1169{
1170 if ( from < 0 || from >= mRanges.size() || to < 0 || to >= mRanges.size() )
1171 return;
1172 mRanges.move( from, to );
1173}
1174
1176{
1177 return r1 < r2;
1178}
1179
1181{
1182 return !valueLessThan( r1, r2 );
1183}
1184
1186{
1187 if ( order == Qt::AscendingOrder )
1188 {
1189 std::sort( mRanges.begin(), mRanges.end(), valueLessThan );
1190 }
1191 else
1192 {
1193 std::sort( mRanges.begin(), mRanges.end(), valueGreaterThan );
1194 }
1195}
1196
1198{
1199 QgsRangeList sortedRanges = mRanges;
1200 std::sort( sortedRanges.begin(), sortedRanges.end(), valueLessThan );
1201
1202 QgsRangeList::const_iterator it = sortedRanges.constBegin();
1203 if ( it == sortedRanges.constEnd() )
1204 return false;
1205
1206 if ( ( *it ).upperValue() < ( *it ).lowerValue() )
1207 return true;
1208
1209 double prevMax = ( *it ).upperValue();
1210 ++it;
1211
1212 for ( ; it != sortedRanges.constEnd(); ++it )
1213 {
1214 if ( ( *it ).upperValue() < ( *it ).lowerValue() )
1215 return true;
1216
1217 if ( ( *it ).lowerValue() < prevMax )
1218 return true;
1219
1220 prevMax = ( *it ).upperValue();
1221 }
1222 return false;
1223}
1224
1226{
1227 QgsRangeList sortedRanges = mRanges;
1228 std::sort( sortedRanges.begin(), sortedRanges.end(), valueLessThan );
1229
1230 QgsRangeList::const_iterator it = sortedRanges.constBegin();
1231 if ( it == sortedRanges.constEnd() )
1232 return false;
1233
1234 double prevMax = ( *it ).upperValue();
1235 ++it;
1236
1237 for ( ; it != sortedRanges.constEnd(); ++it )
1238 {
1239 if ( !qgsDoubleNear( ( *it ).lowerValue(), prevMax ) )
1240 return true;
1241
1242 prevMax = ( *it ).upperValue();
1243 }
1244 return false;
1245}
1246
1248{
1249 return QString::localeAwareCompare( r1.label(), r2.label() ) < 0;
1250}
1251
1253{
1254 return !labelLessThan( r1, r2 );
1255}
1256
1258{
1259 if ( order == Qt::AscendingOrder )
1260 {
1261 std::sort( mRanges.begin(), mRanges.end(), labelLessThan );
1262 }
1263 else
1264 {
1265 std::sort( mRanges.begin(), mRanges.end(), labelGreaterThan );
1266 }
1267}
1268
1273
1278
1280{
1281 QString methodId = methodIdFromMode( mode );
1282 std::unique_ptr< QgsClassificationMethod > method = QgsApplication::classificationMethodRegistry()->method( methodId );
1283 setClassificationMethod( method.release() );
1284}
1285
1287{
1288 mClassificationMethod->setSymmetricMode( useSymmetricMode, mClassificationMethod->symmetryPoint(), mClassificationMethod->symmetryAstride() );
1289}
1290
1292{
1293 mClassificationMethod->setSymmetricMode( mClassificationMethod->symmetricModeEnabled(), symmetryPoint, mClassificationMethod->symmetryAstride() );
1294}
1295
1297{
1298 mClassificationMethod->setSymmetricMode( mClassificationMethod->symmetricModeEnabled(), mClassificationMethod->symmetryPoint(), astride );
1299}
1300
1302{
1303 std::unique_ptr< QgsGraduatedSymbolRenderer > r;
1304 if ( renderer->type() == QLatin1String( "graduatedSymbol" ) )
1305 {
1306 r.reset( static_cast<QgsGraduatedSymbolRenderer *>( renderer->clone() ) );
1307 }
1308 else if ( renderer->type() == QLatin1String( "categorizedSymbol" ) )
1309 {
1310 const QgsCategorizedSymbolRenderer *categorizedSymbolRenderer = dynamic_cast<const QgsCategorizedSymbolRenderer *>( renderer );
1311 if ( categorizedSymbolRenderer )
1312 {
1313 r = std::make_unique< QgsGraduatedSymbolRenderer >( QString(), QgsRangeList() );
1314 if ( categorizedSymbolRenderer->sourceSymbol() )
1315 r->setSourceSymbol( categorizedSymbolRenderer->sourceSymbol()->clone() );
1316 if ( categorizedSymbolRenderer->sourceColorRamp() )
1317 {
1318 bool isRandom = dynamic_cast<const QgsRandomColorRamp *>( categorizedSymbolRenderer->sourceColorRamp() ) ||
1319 dynamic_cast<const QgsLimitedRandomColorRamp *>( categorizedSymbolRenderer->sourceColorRamp() );
1320 if ( !isRandom )
1321 r->setSourceColorRamp( categorizedSymbolRenderer->sourceColorRamp()->clone() );
1322 }
1323 r->setClassAttribute( categorizedSymbolRenderer->classAttribute() );
1324 }
1325 }
1326 else if ( renderer->type() == QLatin1String( "pointDisplacement" ) || renderer->type() == QLatin1String( "pointCluster" ) )
1327 {
1328 const QgsPointDistanceRenderer *pointDistanceRenderer = dynamic_cast<const QgsPointDistanceRenderer *>( renderer );
1329 if ( pointDistanceRenderer )
1330 r.reset( convertFromRenderer( pointDistanceRenderer->embeddedRenderer() ) );
1331 }
1332 else if ( renderer->type() == QLatin1String( "invertedPolygonRenderer" ) )
1333 {
1334 const QgsInvertedPolygonRenderer *invertedPolygonRenderer = dynamic_cast<const QgsInvertedPolygonRenderer *>( renderer );
1335 if ( invertedPolygonRenderer )
1336 r.reset( convertFromRenderer( invertedPolygonRenderer->embeddedRenderer() ) );
1337 }
1338
1339 // If not one of the specifically handled renderers, then just grab the symbol from the renderer
1340 // Could have applied this to specific renderer types (singleSymbol, graduatedSymbol)
1341
1342 if ( !r )
1343 {
1344 r = std::make_unique< QgsGraduatedSymbolRenderer >( QString(), QgsRangeList() );
1345 QgsRenderContext context;
1346 QgsSymbolList symbols = const_cast<QgsFeatureRenderer *>( renderer )->symbols( context );
1347 if ( !symbols.isEmpty() )
1348 {
1349 r->setSourceSymbol( symbols.at( 0 )->clone() );
1350 }
1351 }
1352
1353 renderer->copyRendererData( r.get() );
1354
1355 return r.release();
1356}
1357
1362
1367
1369{
1370 switch ( method )
1371 {
1373 return QStringLiteral( "GraduatedColor" );
1375 return QStringLiteral( "GraduatedSize" );
1376 }
1377 return QString();
1378}
1379
1380
QFlags< FeatureRendererFlag > FeatureRendererFlags
Flags controlling behavior of vector feature renderers.
Definition qgis.h:802
GraduatedMethod
Methods for modifying symbols by range in a graduated symbol renderer.
Definition qgis.h:3200
@ Size
Alter size of symbols.
@ Color
Alter color of symbols.
@ AffectsLabeling
If present, indicates that the renderer will participate in the map labeling problem.
@ Marker
Marker symbol.
@ Line
Line symbol.
@ AffectsLabeling
If present, indicates that the symbol will participate in the map labeling problem.
static QgsClassificationMethodRegistry * classificationMethodRegistry()
Returns the application's classification methods registry, used in graduated renderer.
A vector of attributes.
A feature renderer which represents features using a list of renderer categories.
QgsSymbol * sourceSymbol()
Returns the renderer's source symbol, which is the base symbol used for the each categories' symbol b...
QString classAttribute() const
Returns the class attribute for the renderer, which is the field name or expression string from the l...
QgsColorRamp * sourceColorRamp()
Returns the source color ramp, from which each categories' color is derived.
A dummy implementation class method which does not compute any breaks.
A classification method which uses equal width intervals.
std::unique_ptr< QgsClassificationMethod > method(const QString &id)
Returns a new instance of the method for the given id.
An abstract class for implementations of classification methods.
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...
static std::unique_ptr< QgsClassificationMethod > create(const QDomElement &element, const QgsReadWriteContext &context)
Reads the DOM element and return a new classification method from it.
Q_DECL_DEPRECATED QList< QgsClassificationRange > classes(const QgsVectorLayer *layer, const QString &expression, int nclasses)
This will calculate the classes for a given layer to define the classes.
void setSymmetricMode(bool enabled, double symmetryPoint=0, bool symmetryAstride=false)
Defines if the symmetric mode is enables and configures its parameters.
ClassPosition
Defines the class position.
@ LowerBound
The class is at the lower bound.
@ UpperBound
The class is at the upper bound.
@ Inner
The class is not at a bound.
static QList< double > rangesToBreaks(const QList< QgsClassificationRange > &classes)
Transforms a list of classes to a list of breaks.
Abstract base class for color ramps.
virtual QgsColorRamp * clone() const =0
Creates a clone of the color ramp.
Object that keeps configuration of appearance of marker symbol's data-defined size in legend.
static QgsDataDefinedSizeLegend * readXml(const QDomElement &elem, const QgsReadWriteContext &context) SIP_FACTORY
Creates instance from given element and returns it (caller takes ownership). Returns nullptr on error...
void updateFromSymbolAndProperty(const QgsMarkerSymbol *symbol, const QgsProperty &ddSize)
Updates the list of classes, source symbol and title label from given symbol and property.
QgsLegendSymbolList legendSymbolList() const
Generates legend symbol items according to the configuration.
static QList< QgsExpressionContextScope * > globalProjectLayerScopes(const QgsMapLayer *layer)
Creates a list of three scopes: global, layer's project and layer.
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
void appendScopes(const QList< QgsExpressionContextScope * > &scopes)
Appends a list of scopes to the end of the context.
Handles parsing and evaluation of expressions (formerly called "search strings").
bool prepare(const QgsExpressionContext *context)
Gets the expression ready for evaluation - find out column indexes.
static QString quotedValue(const QVariant &value)
Returns a string representation of a literal value, including appropriate quotations where required.
static QString quoteFieldExpression(const QString &expression, const QgsVectorLayer *layer)
Validate if the expression is a field in the layer and ensure it is quoted.
bool hasParserError() const
Returns true if an error occurred when parsing the input expression.
QSet< QString > referencedColumns() const
Gets list of columns referenced by the expression.
bool needsGeometry() const
Returns true if the expression uses feature geometry for some computation.
Abstract base class for all 2D vector feature renderers.
virtual void stopRender(QgsRenderContext &context)
Must be called when a render cycle has finished, to allow the renderer to clean up.
QString type() const
void copyRendererData(QgsFeatureRenderer *destRenderer) const
Clones generic renderer data to another renderer.
static void convertSymbolRotation(QgsSymbol *symbol, const QString &field)
void saveRendererData(QDomDocument &doc, QDomElement &element, const QgsReadWriteContext &context)
Saves generic renderer data into the specified element.
virtual void startRender(QgsRenderContext &context, const QgsFields &fields)
Must be called when a new render cycle is started.
static void convertSymbolSizeScale(QgsSymbol *symbol, Qgis::ScaleMethod method, const QString &field)
virtual QgsFeatureRenderer * clone() const =0
Create a deep copy of this renderer.
The feature class encapsulates a single feature including its unique ID, geometry and a list of field...
Definition qgsfeature.h:58
QgsAttributes attributes
Definition qgsfeature.h:67
Container of fields for a vector layer.
Definition qgsfields.h:46
Q_INVOKABLE int lookupField(const QString &fieldName) const
Looks up field's index from the field name.
A vector feature renderer which uses numeric attributes to classify features into different ranges.
QgsLegendSymbolList legendSymbolItems() const override
Returns a list of symbology items for the legend.
QgsSymbol * sourceSymbol()
Returns the renderer's source symbol, which is the base symbol used for the each classes' symbol befo...
QDomElement save(QDomDocument &doc, const QgsReadWriteContext &context) override
Stores renderer properties to an XML element.
void updateSymbols(QgsSymbol *sym)
Update all the symbols but leave breaks and colors.
const QgsRendererRange * rangeForValue(double value) const
Returns the renderer range matching the provided value, or nullptr if no range matches the value.
QgsColorRamp * sourceColorRamp()
Returns the source color ramp, from which each classes' color is derived.
bool updateRangeSymbol(int rangeIndex, QgsSymbol *symbol)
void addBreak(double breakValue, bool updateSymbols=true)
Add a breakpoint by splitting existing classes so that the specified value becomes a break between tw...
Q_DECL_DEPRECATED void setAstride(bool astride)
Set if we want a central class astride the pivot value.
void setClassificationMethod(QgsClassificationMethod *method)
Defines the classification method This will take ownership of the method.
static Q_DECL_DEPRECATED QList< double > calcEqualIntervalBreaks(double minimum, double maximum, int classes, bool useSymmetricMode, double symmetryPoint, bool astride)
Compute the equal interval classification.
QgsGraduatedSymbolRenderer * clone() const override
Create a deep copy of this renderer.
std::unique_ptr< QgsDataDefinedSizeLegend > mDataDefinedSizeLegend
static Q_DECL_DEPRECATED 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 startRender(QgsRenderContext &context, const QgsFields &fields) override
Must be called when a new render cycle is started.
double maxSymbolSize() const
Returns the max symbol size when graduated by size.
Q_DECL_DEPRECATED bool useSymmetricMode() const
Returns if we want to classify symmetric around a given value.
bool updateRangeLabel(int rangeIndex, const QString &label)
QgsClassificationMethod * classificationMethod() const
Returns the classification method.
QgsSymbol * originalSymbolForFeature(const QgsFeature &feature, QgsRenderContext &context) const override
Returns symbol for feature.
void sortByValue(Qt::SortOrder order=Qt::AscendingOrder)
void toSld(QDomDocument &doc, QDomElement &element, const QVariantMap &props=QVariantMap()) const override
used from subclasses to create SLD Rule elements following SLD v1.1 specs
void checkLegendSymbolItem(const QString &key, bool state=true) override
Sets whether the legend symbology item with the specified ley should be checked.
std::unique_ptr< QgsSymbol > mSourceSymbol
void setLegendSymbolItem(const QString &key, QgsSymbol *symbol) override
Sets the symbol to be used for a legend symbol item.
Qgis::FeatureRendererFlags flags() const override
Returns flags associated with the renderer.
void setGraduatedMethod(Qgis::GraduatedMethod method)
Set the method used for graduation (either size or color).
static QgsFeatureRenderer * create(QDomElement &element, const QgsReadWriteContext &context)
create renderer from XML element
Q_DECL_DEPRECATED void setMode(Mode mode)
QSet< QString > legendKeysForFeature(const QgsFeature &feature, QgsRenderContext &context) const override
Returns legend keys matching a specified feature.
bool rangesOverlap() const
Tests whether classes assigned to the renderer have ranges which overlap.
std::shared_ptr< QgsClassificationMethod > mClassificationMethod
Q_DECL_DEPRECATED bool astride() const
Returns if we want to have a central class astride the pivot value.
Q_DECL_DEPRECATED void setLabelFormat(const QgsRendererRangeLabelFormat &labelFormat, bool updateRanges=false)
Set the label format used to generate default classification labels.
Q_DECL_DEPRECATED void updateClasses(QgsVectorLayer *vlayer, Mode mode, int nclasses, bool useSymmetricMode=false, double symmetryPoint=0.0, bool astride=false)
Recalculate classes for a layer.
QString dump() const override
Returns debug information about this renderer.
bool updateRangeUpperValue(int rangeIndex, double value)
QString legendKeyToExpression(const QString &key, QgsVectorLayer *layer, bool &ok) const override
Attempts to convert the specified legend rule key to a QGIS expression matching the features displaye...
QString legendKeyForValue(double value) const
Returns the matching legend key for a value.
void setSourceColorRamp(QgsColorRamp *ramp)
Sets the source color ramp.
void setSourceSymbol(QgsSymbol *sym)
Sets the source symbol for the renderer, which is the base symbol used for the each classes' symbol b...
bool legendSymbolItemChecked(const QString &key) override
Returns true if the legend symbology item with the specified key is checked.
bool updateRangeLowerValue(int rangeIndex, double value)
void stopRender(QgsRenderContext &context) override
Must be called when a render cycle has finished, to allow the renderer to clean up.
static QgsGraduatedSymbolRenderer * convertFromRenderer(const QgsFeatureRenderer *renderer)
creates a QgsGraduatedSymbolRenderer from an existing renderer.
bool legendSymbolItemsCheckable() const override
Returns true if symbology items in legend are checkable.
void moveClass(int from, int to)
Moves the category at index position from to index position to.
void sortByLabel(Qt::SortOrder order=Qt::AscendingOrder)
QSet< QString > usedAttributes(const QgsRenderContext &context) const override
Returns a list of attributes required by this renderer.
void updateRangeLabels()
Updates the labels of the ranges.
bool updateRangeRenderState(int rangeIndex, bool render)
QgsSymbol * symbolForFeature(const QgsFeature &feature, QgsRenderContext &context) const override
To be overridden.
std::unique_ptr< QgsColorRamp > mSourceColorRamp
QgsSymbolList symbols(QgsRenderContext &context) const override
Returns list of symbols used by the renderer.
bool accept(QgsStyleEntityVisitorInterface *visitor) const override
Accepts the specified symbology visitor, causing it to visit all symbols associated with the renderer...
QgsDataDefinedSizeLegend * dataDefinedSizeLegend() const
Returns configuration of appearance of legend when using data-defined size for marker symbols.
void updateColorRamp(QgsColorRamp *ramp=nullptr)
Update the color ramp used.
Q_DECL_DEPRECATED Mode mode() const
QgsGraduatedSymbolRenderer(const QString &attrName=QString(), const QgsRangeList &ranges=QgsRangeList())
double minSymbolSize() const
Returns the min symbol size when graduated by size.
Qgis::GraduatedMethod graduatedMethod() const
Returns the method used for graduation (either size or color).
bool filterNeedsGeometry() const override
Returns true if this renderer requires the geometry to apply the filter.
int mAttrNum
attribute index (derived from attribute name in startRender)
Q_DECL_DEPRECATED void setSymmetryPoint(double symmetryPoint)
Set the pivot point.
std::unique_ptr< QgsExpression > mExpression
static QString graduatedMethodStr(Qgis::GraduatedMethod method)
void setSymbolSizes(double minSize, double maxSize)
set varying symbol size for classes
void calculateLabelPrecision(bool updateRanges=true)
Reset the label decimal places to a numberbased on the minimum class interval.
void setDataDefinedSizeLegend(QgsDataDefinedSizeLegend *settings)
Configures appearance of legend when renderer is configured to use data-defined size for marker symbo...
const QgsRangeList & ranges() const
Returns a list of all ranges used in the classification.
Q_DECL_DEPRECATED QgsRendererRangeLabelFormat labelFormat() const
Returns the label format used to generate default classification labels.
static Q_DECL_DEPRECATED QgsGraduatedSymbolRenderer * createRenderer(QgsVectorLayer *vlayer, const QString &attrName, int classes, Mode mode, QgsSymbol *symbol, QgsColorRamp *ramp, const QgsRendererRangeLabelFormat &legendFormat=QgsRendererRangeLabelFormat(), bool useSymmetricMode=false, double symmetryPoint=0.0, const QStringList &listForCboPrettyBreaks=QStringList(), bool astride=false)
Creates a new graduated renderer.
Q_DECL_DEPRECATED double symmetryPoint() const
Returns the pivot value for symmetric classification.
Q_DECL_DEPRECATED void setUseSymmetricMode(bool useSymmetricMode)
Set if we want to classify symmetric around a given value.
QgsSymbol * symbolForValue(double value) const
Gets the symbol which is used to represent value.
bool rangesHaveGaps() const
Tests whether classes assigned to the renderer have gaps between the ranges.
A polygon-only feature renderer used to display features inverted.
Stores information about one class/rule of a vector layer renderer in a unified way that can be used ...
Constrained random color ramp, which returns random colors based on preset parameters.
A line symbol type, for rendering LineString and MultiLineString geometries.
double width() const
Returns the estimated width for the whole symbol, which is the maximum width of all marker symbol lay...
A marker symbol type, for rendering Point and MultiPoint geometries.
double size() const
Returns the estimated size for the whole symbol, which is the maximum size of all marker symbol layer...
QgsProperty dataDefinedSize() const
Returns data defined size for whole symbol (including all symbol layers).
const QgsFeatureRenderer * embeddedRenderer() const override
Returns the current embedded renderer (subrenderer) for this feature renderer.
An abstract base class for distance based point renderers (e.g., clusterer and displacement renderers...
const QgsFeatureRenderer * embeddedRenderer() const override
Returns the current embedded renderer (subrenderer) for this feature renderer.
A store for object properties.
bool isActive() const
Returns whether the property is currently active.
A color ramp consisting of random colors, constrained within component ranges.
A container for the context for various read/write operations on objects.
Contains information about the context of a rendering operation.
double rendererScale() const
Returns the renderer map scale.
QgsExpressionContext & expressionContext()
Gets the expression context.
Encapsulates the formatting for a QgsRendererRange label.
Represents a value range for a QgsGraduatedSymbolRenderer.
void setUpperValue(double upperValue)
Sets the upper bound of the range.
QString label() const
Returns the label used for the range.
void setSymbol(QgsSymbol *s)
Sets the symbol used for the range.
QgsSymbol * symbol() const
Returns the symbol used for the range.
void setLabel(const QString &label)
Sets the label used for the range.
bool renderState() const
Returns true if the range should be rendered.
double upperValue() const
Returns the upper bound of the range.
void setLowerValue(double lowerValue)
Sets the lower bound of the range.
QString uuid() const
Returns the unique identifier for this range.
double lowerValue() const
Returns the lower bound of the range.
A color ramp entity for QgsStyle databases.
Definition qgsstyle.h:1429
An interface for classes which can visit style entity (e.g.
virtual bool visit(const QgsStyleEntityVisitorInterface::StyleLeaf &entity)
Called when the visitor will visit a style entity.
A symbol entity for QgsStyle databases.
Definition qgsstyle.h:1397
static std::unique_ptr< QgsColorRamp > loadColorRamp(QDomElement &element)
Creates a color ramp from the settings encoded in an XML element.
static Qgis::ScaleMethod decodeScaleMethod(const QString &str)
Decodes a symbol scale method from a string.
static QDomElement saveColorRamp(const QString &name, const QgsColorRamp *ramp, QDomDocument &doc)
Encodes a color ramp's settings to an XML element.
static void clearSymbolMap(QgsSymbolMap &symbols)
static QgsSymbolMap loadSymbols(QDomElement &element, const QgsReadWriteContext &context)
Reads a collection of symbols from XML and returns them in a map. Caller is responsible for deleting ...
static QDomElement saveSymbols(QgsSymbolMap &symbols, const QString &tagName, QDomDocument &doc, const QgsReadWriteContext &context)
Writes a collection of symbols to XML with specified tagName for the top-level element.
Abstract base class for all rendered symbols.
Definition qgssymbol.h:231
void setColor(const QColor &color) const
Sets the color for the symbol.
QSet< QString > usedAttributes(const QgsRenderContext &context) const
Returns a list of attributes required to render this feature.
virtual QgsSymbol * clone() const =0
Returns a deep copy of this symbol.
static QgsSymbol * defaultSymbol(Qgis::GeometryType geomType)
Returns a new default symbol for the specified geometry type.
static bool isNull(const QVariant &variant, bool silenceNullWarnings=false)
Returns true if the specified variant should be considered a NULL value.
Represents a vector layer which manages a vector based dataset.
Q_INVOKABLE Qgis::GeometryType geometryType() const
Returns point, line or polygon.
#define Q_NOWARN_DEPRECATED_POP
Definition qgis.h:6819
#define Q_NOWARN_DEPRECATED_PUSH
Definition qgis.h:6818
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)
Definition qgis.h:6286
#define SIP_DEPRECATED
Definition qgis_sip.h:106
bool labelGreaterThan(const QgsRendererCategory &c1, const QgsRendererCategory &c2)
bool valueLessThan(const QgsRendererCategory &c1, const QgsRendererCategory &c2)
bool valueGreaterThan(const QgsRendererCategory &c1, const QgsRendererCategory &c2)
bool labelLessThan(const QgsRendererCategory &c1, const QgsRendererCategory &c2)
bool valueLessThan(const QgsRendererRange &r1, const QgsRendererRange &r2)
bool labelGreaterThan(const QgsRendererRange &r1, const QgsRendererRange &r2)
bool labelLessThan(const QgsRendererRange &r1, const QgsRendererRange &r2)
bool valueGreaterThan(const QgsRendererRange &r1, const QgsRendererRange &r2)
QList< QgsLegendSymbolItem > QgsLegendSymbolList
#define RENDERER_TAG_NAME
Definition qgsrenderer.h:53
QMap< QString, QgsSymbol * > QgsSymbolMap
Definition qgsrenderer.h:48
QList< QgsSymbol * > QgsSymbolList
Definition qgsrenderer.h:47
QList< QgsRendererRange > QgsRangeList
int precision
Contains information relating to the style entity currently being visited.