QGIS API Documentation 3.37.0-Master (fdefdf9c27f)
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 "qgslogger.h"
33#include "qgspainteffect.h"
36#include "qgsproperty.h"
37#include "qgssymbol.h"
38#include "qgssymbollayer.h"
39#include "qgssymbollayerutils.h"
41#include "qgsvectorlayer.h"
42#include "qgsvectorlayerutils.h"
47#include "qgsapplication.h"
50#include "qgsmarkersymbol.h"
51#include "qgslinesymbol.h"
52
54 : QgsFeatureRenderer( QStringLiteral( "graduatedSymbol" ) )
55 , mAttrName( attrName )
56{
57 // TODO: check ranges for sanity (NULL symbols, invalid ranges)
58
59 //important - we need a deep copy of the ranges list, not a shared copy. This is required because
60 //QgsRendererRange::symbol() is marked const, and so retrieving the symbol via this method does not
61 //trigger a detachment and copy of mRanges BUT that same method CAN be used to modify a symbol in place
62 const auto constRanges = ranges;
63 for ( const QgsRendererRange &range : constRanges )
64 {
65 mRanges << range;
66 }
67
69}
70
72{
73 mRanges.clear(); // should delete all the symbols
74}
75
76
78{
79 for ( const QgsRendererRange &range : mRanges )
80 {
81 if ( range.lowerValue() <= value && range.upperValue() >= value )
82 {
83 if ( range.renderState() || mCounting )
84 return &range;
85 else
86 return nullptr;
87 }
88 }
89
90 // second chance -- use a bit of double tolerance to avoid floating point equality fuzziness
91 // if a value falls just outside of a range, but within acceptable double precision tolerance
92 // then we accept it anyway
93 for ( const QgsRendererRange &range : mRanges )
94 {
95 if ( qgsDoubleNear( range.lowerValue(), value ) || qgsDoubleNear( range.upperValue(), value ) )
96 {
97 if ( range.renderState() || mCounting )
98 return &range;
99 else
100 return nullptr;
101 }
102 }
103 // the value is out of the range: return NULL instead of symbol
104 return nullptr;
105}
106
108{
109 if ( const QgsRendererRange *range = rangeForValue( value ) )
110 return range->symbol();
111 return nullptr;
112}
113
115{
116 if ( const QgsRendererRange *matchingRange = rangeForValue( value ) )
117 {
118 for ( const QgsRendererRange &range : mRanges )
119 {
120 if ( matchingRange == &range )
121 return range.uuid();
122 }
123 }
124 return QString();
125}
126
128{
129 return originalSymbolForFeature( feature, context );
130}
131
132QVariant QgsGraduatedSymbolRenderer::valueForFeature( const QgsFeature &feature, QgsRenderContext &context ) const
133{
134 QgsAttributes attrs = feature.attributes();
135 QVariant value;
136 if ( mExpression )
137 {
138 value = mExpression->evaluate( &context.expressionContext() );
139 }
140 else
141 {
142 value = attrs.value( mAttrNum );
143 }
144
145 return value;
146}
147
149{
150 QVariant value = valueForFeature( feature, context );
151
152 // Null values should not be categorized
153 if ( QgsVariantUtils::isNull( value ) )
154 return nullptr;
155
156 // find the right category
157 return symbolForValue( value.toDouble() );
158}
159
161{
162 QgsFeatureRenderer::startRender( context, fields );
163
164 mCounting = context.rendererScale() == 0.0;
165
166 // find out classification attribute index from name
167 mAttrNum = fields.lookupField( mAttrName );
168
169 if ( mAttrNum == -1 )
170 {
171 mExpression.reset( new QgsExpression( mAttrName ) );
172 mExpression->prepare( &context.expressionContext() );
173 }
174
175 for ( const QgsRendererRange &range : std::as_const( mRanges ) )
176 {
177 if ( !range.symbol() )
178 continue;
179
180 range.symbol()->startRender( context, fields );
181 }
182}
183
185{
187
188 for ( const QgsRendererRange &range : std::as_const( mRanges ) )
189 {
190 if ( !range.symbol() )
191 continue;
192
193 range.symbol()->stopRender( context );
194 }
195}
196
198{
199 QSet<QString> attributes;
200
201 // mAttrName can contain either attribute name or an expression.
202 // Sometimes it is not possible to distinguish between those two,
203 // e.g. "a - b" can be both a valid attribute name or expression.
204 // Since we do not have access to fields here, try both options.
205 attributes << mAttrName;
206
207 QgsExpression testExpr( mAttrName );
208 if ( !testExpr.hasParserError() )
209 attributes.unite( testExpr.referencedColumns() );
210
211 QgsRangeList::const_iterator range_it = mRanges.constBegin();
212 for ( ; range_it != mRanges.constEnd(); ++range_it )
213 {
214 QgsSymbol *symbol = range_it->symbol();
215 if ( symbol )
216 {
217 attributes.unite( symbol->usedAttributes( context ) );
218 }
219 }
220 return attributes;
221}
222
224{
225 QgsExpression testExpr( mAttrName );
226 if ( !testExpr.hasParserError() )
227 {
228 QgsExpressionContext context;
229 context.appendScopes( QgsExpressionContextUtils::globalProjectLayerScopes( nullptr ) ); // unfortunately no layer access available!
230 testExpr.prepare( &context );
231 return testExpr.needsGeometry();
232 }
233 return false;
234}
235
237{
238 if ( rangeIndex < 0 || rangeIndex >= mRanges.size() )
239 return false;
240 mRanges[rangeIndex].setSymbol( symbol );
241 return true;
242}
243
244bool QgsGraduatedSymbolRenderer::updateRangeLabel( int rangeIndex, const QString &label )
245{
246 if ( rangeIndex < 0 || rangeIndex >= mRanges.size() )
247 return false;
248 mRanges[rangeIndex].setLabel( label );
249 return true;
250}
251
252bool QgsGraduatedSymbolRenderer::updateRangeUpperValue( int rangeIndex, double value )
253{
254 if ( rangeIndex < 0 || rangeIndex >= mRanges.size() )
255 return false;
256 QgsRendererRange &range = mRanges[rangeIndex];
258 if ( rangeIndex == 0 )
260 else if ( rangeIndex == mRanges.count() )
262
263 bool isDefaultLabel = mClassificationMethod->labelForRange( range, pos ) == range.label();
264 range.setUpperValue( value );
265 if ( isDefaultLabel )
266 range.setLabel( mClassificationMethod->labelForRange( range, pos ) );
267
268 return true;
269}
270
271bool QgsGraduatedSymbolRenderer::updateRangeLowerValue( int rangeIndex, double value )
272{
273 if ( rangeIndex < 0 || rangeIndex >= mRanges.size() )
274 return false;
275
276 QgsRendererRange &range = mRanges[rangeIndex];
278 if ( rangeIndex == 0 )
280 else if ( rangeIndex == mRanges.count() )
282
283 bool isDefaultLabel = mClassificationMethod->labelForRange( range, pos ) == range.label();
284 range.setLowerValue( value );
285 if ( isDefaultLabel )
286 range.setLabel( mClassificationMethod->labelForRange( range, pos ) );
287
288 return true;
289}
290
292{
293 if ( rangeIndex < 0 || rangeIndex >= mRanges.size() )
294 return false;
295 mRanges[rangeIndex].setRenderState( value );
296 return true;
297}
298
300{
301 QString s = QStringLiteral( "GRADUATED: attr %1\n" ).arg( mAttrName );
302 for ( int i = 0; i < mRanges.count(); i++ )
303 s += mRanges[i].dump();
304 return s;
305}
306
308{
310
312
313 if ( mSourceSymbol )
314 r->setSourceSymbol( mSourceSymbol->clone() );
315 if ( mSourceColorRamp )
316 {
318 }
321 copyRendererData( r );
322 return r;
323}
324
325void QgsGraduatedSymbolRenderer::toSld( QDomDocument &doc, QDomElement &element, const QVariantMap &props ) const
326{
327 QVariantMap newProps = props;
328 newProps[ QStringLiteral( "attribute" )] = mAttrName;
329 newProps[ QStringLiteral( "method" )] = graduatedMethodStr( mGraduatedMethod );
330
331 // create a Rule for each range
332 bool first = true;
333 for ( QgsRangeList::const_iterator it = mRanges.constBegin(); it != mRanges.constEnd(); ++it )
334 {
335 it->toSld( doc, element, newProps, first );
336 first = false;
337 }
338}
339
341{
342 Q_UNUSED( context )
343 QgsSymbolList lst;
344 lst.reserve( mRanges.count() );
345 for ( const QgsRendererRange &range : std::as_const( mRanges ) )
346 {
347 lst.append( range.symbol() );
348 }
349 return lst;
350}
351
353{
354 for ( const QgsRendererRange &range : std::as_const( mRanges ) )
355 {
356 QgsStyleSymbolEntity entity( range.symbol() );
357 if ( !visitor->visit( QgsStyleEntityVisitorInterface::StyleLeaf( &entity, QStringLiteral( "%1 - %2" ).arg( range.lowerValue() ).arg( range.upperValue() ), range.label() ) ) )
358 return false;
359 }
360
361 if ( mSourceColorRamp )
362 {
364 if ( !visitor->visit( QgsStyleEntityVisitorInterface::StyleLeaf( &entity ) ) )
365 return false;
366 }
367
368 return true;
369}
370
371void QgsGraduatedSymbolRenderer::makeBreaksSymmetric( QList<double> &breaks, double symmetryPoint, bool astride )
372{
374}
375
376QList<double> QgsGraduatedSymbolRenderer::calcEqualIntervalBreaks( double minimum, double maximum, int classes, bool useSymmetricMode, double symmetryPoint, bool astride )
377{
380 QList<QgsClassificationRange> _classes = method.classes( minimum, maximum, classes );
382}
383
386 QgsVectorLayer *vlayer,
387 const QString &attrName,
388 int classes,
389 Mode mode,
390 QgsSymbol *symbol,
391 QgsColorRamp *ramp,
392 const QgsRendererRangeLabelFormat &labelFormat,
393 bool useSymmetricMode,
394 double symmetryPoint,
395 const QStringList &listForCboPrettyBreaks,
396 bool astride
397)
398{
399 Q_UNUSED( listForCboPrettyBreaks )
400
403 r->setSourceSymbol( symbol->clone() );
404 r->setSourceColorRamp( ramp->clone() );
405
406 QString methodId = methodIdFromMode( mode );
408
409 if ( method )
410 {
412 method->setLabelFormat( labelFormat.format() );
415 }
416 r->setClassificationMethod( method );
417
418 r->updateClasses( vlayer, classes );
419 return r;
420}
422
424 bool useSymmetricMode, double symmetryPoint, bool astride )
425{
426 if ( mAttrName.isEmpty() )
427 return;
428
429 QString methodId = methodIdFromMode( mode );
432 setClassificationMethod( method );
433
434 updateClasses( vlayer, nclasses );
435}
436
438{
440 return;
441
442 QList<QgsClassificationRange> classes = mClassificationMethod->classes( vl, mAttrName, nclasses );
443
445
446 for ( QList<QgsClassificationRange>::iterator it = classes.begin(); it != classes.end(); ++it )
447 {
449 addClass( QgsRendererRange( *it, newSymbol ) );
450 }
451 updateColorRamp( nullptr );
452}
453
456{
457 return QgsRendererRangeLabelFormat( mClassificationMethod->labelFormat(), mClassificationMethod->labelPrecision(), mClassificationMethod->labelTrimTrailingZeroes() );
458}
460
462{
463 QDomElement symbolsElem = element.firstChildElement( QStringLiteral( "symbols" ) );
464 if ( symbolsElem.isNull() )
465 return nullptr;
466
467 QDomElement rangesElem = element.firstChildElement( QStringLiteral( "ranges" ) );
468 if ( rangesElem.isNull() )
469 return nullptr;
470
471 QgsSymbolMap symbolMap = QgsSymbolLayerUtils::loadSymbols( symbolsElem, context );
473
474 QDomElement rangeElem = rangesElem.firstChildElement();
475 int i = 0;
476 while ( !rangeElem.isNull() )
477 {
478 if ( rangeElem.tagName() == QLatin1String( "range" ) )
479 {
480 double lowerValue = rangeElem.attribute( QStringLiteral( "lower" ) ).toDouble();
481 double upperValue = rangeElem.attribute( QStringLiteral( "upper" ) ).toDouble();
482 QString symbolName = rangeElem.attribute( QStringLiteral( "symbol" ) );
483 QString label = rangeElem.attribute( QStringLiteral( "label" ) );
484 bool render = rangeElem.attribute( QStringLiteral( "render" ), QStringLiteral( "true" ) ) != QLatin1String( "false" );
485 QString uuid = rangeElem.attribute( QStringLiteral( "uuid" ), QString::number( i++ ) );
486 if ( symbolMap.contains( symbolName ) )
487 {
488 QgsSymbol *symbol = symbolMap.take( symbolName );
489 ranges.append( QgsRendererRange( lowerValue, upperValue, symbol, label, render, uuid ) );
490 }
491 }
492 rangeElem = rangeElem.nextSiblingElement();
493 }
494
495 QString attrName = element.attribute( QStringLiteral( "attr" ) );
496
498
499 QString attrMethod = element.attribute( QStringLiteral( "graduatedMethod" ) );
500 if ( !attrMethod.isEmpty() )
501 {
504 else if ( attrMethod == graduatedMethodStr( Qgis::GraduatedMethod::Size ) )
506 }
507
508
509 // delete symbols if there are any more
511
512 // try to load source symbol (optional)
513 QDomElement sourceSymbolElem = element.firstChildElement( QStringLiteral( "source-symbol" ) );
514 if ( !sourceSymbolElem.isNull() )
515 {
516 QgsSymbolMap sourceSymbolMap = QgsSymbolLayerUtils::loadSymbols( sourceSymbolElem, context );
517 if ( sourceSymbolMap.contains( QStringLiteral( "0" ) ) )
518 {
519 r->setSourceSymbol( sourceSymbolMap.take( QStringLiteral( "0" ) ) );
520 }
521 QgsSymbolLayerUtils::clearSymbolMap( sourceSymbolMap );
522 }
523
524 // try to load color ramp (optional)
525 QDomElement sourceColorRampElem = element.firstChildElement( QStringLiteral( "colorramp" ) );
526 if ( !sourceColorRampElem.isNull() && sourceColorRampElem.attribute( QStringLiteral( "name" ) ) == QLatin1String( "[source]" ) )
527 {
528 r->setSourceColorRamp( QgsSymbolLayerUtils::loadColorRamp( sourceColorRampElem ) );
529 }
530
531 // try to load mode
532
533 QDomElement modeElem = element.firstChildElement( QStringLiteral( "mode" ) ); // old format, backward compatibility
534 QDomElement methodElem = element.firstChildElement( QStringLiteral( "classificationMethod" ) );
535 QgsClassificationMethod *method = nullptr;
536
537 // TODO QGIS 4 Remove
538 // backward compatibility for QGIS project < 3.10
539 if ( !modeElem.isNull() )
540 {
541 QString modeString = modeElem.attribute( QStringLiteral( "name" ) );
542 QString methodId;
543 // the strings saved in the project does not match with the old Mode enum
544 if ( modeString == QLatin1String( "equal" ) )
545 methodId = QStringLiteral( "EqualInterval" );
546 else if ( modeString == QLatin1String( "quantile" ) )
547 methodId = QStringLiteral( "Quantile" );
548 else if ( modeString == QLatin1String( "jenks" ) )
549 methodId = QStringLiteral( "Jenks" );
550 else if ( modeString == QLatin1String( "stddev" ) )
551 methodId = QStringLiteral( "StdDev" );
552 else if ( modeString == QLatin1String( "pretty" ) )
553 methodId = QStringLiteral( "Pretty" );
554
556
557 // symmetric mode
558 QDomElement symmetricModeElem = element.firstChildElement( QStringLiteral( "symmetricMode" ) );
559 if ( !symmetricModeElem.isNull() )
560 {
561 // symmetry
562 QString symmetricEnabled = symmetricModeElem.attribute( QStringLiteral( "enabled" ) );
563 QString symmetricPointString = symmetricModeElem.attribute( QStringLiteral( "symmetryPoint" ) );
564 QString astrideEnabled = symmetricModeElem.attribute( QStringLiteral( "astride" ) );
565 method->setSymmetricMode( symmetricEnabled == QLatin1String( "true" ), symmetricPointString.toDouble(), astrideEnabled == QLatin1String( "true" ) );
566 }
567 QDomElement labelFormatElem = element.firstChildElement( QStringLiteral( "labelformat" ) );
568 if ( !labelFormatElem.isNull() )
569 {
570 // label format
571 QString format = labelFormatElem.attribute( QStringLiteral( "format" ), "%1" + QStringLiteral( " - " ) + "%2" );
572 int precision = labelFormatElem.attribute( QStringLiteral( "decimalplaces" ), QStringLiteral( "4" ) ).toInt();
573 bool trimTrailingZeroes = labelFormatElem.attribute( QStringLiteral( "trimtrailingzeroes" ), QStringLiteral( "false" ) ) == QLatin1String( "true" );
574 method->setLabelFormat( format );
575 method->setLabelPrecision( precision );
576 method->setLabelTrimTrailingZeroes( trimTrailingZeroes );
577 }
578 // End of backward compatibility
579 }
580 else
581 {
582 // QGIS project 3.10+
583 method = QgsClassificationMethod::create( methodElem, context );
584 }
585
586 // apply the method
587 r->setClassificationMethod( method );
588
589 QDomElement rotationElem = element.firstChildElement( QStringLiteral( "rotation" ) );
590 if ( !rotationElem.isNull() && !rotationElem.attribute( QStringLiteral( "field" ) ).isEmpty() )
591 {
592 for ( const QgsRendererRange &range : std::as_const( r->mRanges ) )
593 {
594 convertSymbolRotation( range.symbol(), rotationElem.attribute( QStringLiteral( "field" ) ) );
595 }
596 if ( r->mSourceSymbol )
597 {
598 convertSymbolRotation( r->mSourceSymbol.get(), rotationElem.attribute( QStringLiteral( "field" ) ) );
599 }
600 }
601 QDomElement sizeScaleElem = element.firstChildElement( QStringLiteral( "sizescale" ) );
602 if ( !sizeScaleElem.isNull() && !sizeScaleElem.attribute( QStringLiteral( "field" ) ).isEmpty() )
603 {
604 for ( const QgsRendererRange &range : std::as_const( r->mRanges ) )
605 {
606 convertSymbolSizeScale( range.symbol(),
607 QgsSymbolLayerUtils::decodeScaleMethod( sizeScaleElem.attribute( QStringLiteral( "scalemethod" ) ) ),
608 sizeScaleElem.attribute( QStringLiteral( "field" ) ) );
609 }
610 if ( r->mSourceSymbol && r->mSourceSymbol->type() == Qgis::SymbolType::Marker )
611 {
613 QgsSymbolLayerUtils::decodeScaleMethod( sizeScaleElem.attribute( QStringLiteral( "scalemethod" ) ) ),
614 sizeScaleElem.attribute( QStringLiteral( "field" ) ) );
615 }
616 }
617
618 QDomElement ddsLegendSizeElem = element.firstChildElement( QStringLiteral( "data-defined-size-legend" ) );
619 if ( !ddsLegendSizeElem.isNull() )
620 {
621 r->mDataDefinedSizeLegend.reset( QgsDataDefinedSizeLegend::readXml( ddsLegendSizeElem, context ) );
622 }
623// TODO: symbol levels
624 return r;
625}
626
627QDomElement QgsGraduatedSymbolRenderer::save( QDomDocument &doc, const QgsReadWriteContext &context )
628{
629 QDomElement rendererElem = doc.createElement( RENDERER_TAG_NAME );
630 rendererElem.setAttribute( QStringLiteral( "type" ), QStringLiteral( "graduatedSymbol" ) );
631 rendererElem.setAttribute( QStringLiteral( "attr" ), mAttrName );
632 rendererElem.setAttribute( QStringLiteral( "graduatedMethod" ), graduatedMethodStr( mGraduatedMethod ) );
633
634 // ranges
635 int i = 0;
637 QDomElement rangesElem = doc.createElement( QStringLiteral( "ranges" ) );
638 QgsRangeList::const_iterator it = mRanges.constBegin();
639 for ( ; it != mRanges.constEnd(); ++it )
640 {
641 const QgsRendererRange &range = *it;
642 QString symbolName = QString::number( i );
643 symbols.insert( symbolName, range.symbol() );
644
645 QDomElement rangeElem = doc.createElement( QStringLiteral( "range" ) );
646 rangeElem.setAttribute( QStringLiteral( "lower" ), QString::number( range.lowerValue(), 'f', 15 ) );
647 rangeElem.setAttribute( QStringLiteral( "upper" ), QString::number( range.upperValue(), 'f', 15 ) );
648 rangeElem.setAttribute( QStringLiteral( "symbol" ), symbolName );
649 rangeElem.setAttribute( QStringLiteral( "label" ), range.label() );
650 rangeElem.setAttribute( QStringLiteral( "render" ), range.renderState() ? QStringLiteral( "true" ) : QStringLiteral( "false" ) );
651 rangeElem.setAttribute( QStringLiteral( "uuid" ), range.uuid() );
652 rangesElem.appendChild( rangeElem );
653 i++;
654 }
655
656 rendererElem.appendChild( rangesElem );
657
658 // save symbols
659 QDomElement symbolsElem = QgsSymbolLayerUtils::saveSymbols( symbols, QStringLiteral( "symbols" ), doc, context );
660 rendererElem.appendChild( symbolsElem );
661
662 // save source symbol
663 if ( mSourceSymbol )
664 {
665 QgsSymbolMap sourceSymbols;
666 sourceSymbols.insert( QStringLiteral( "0" ), mSourceSymbol.get() );
667 QDomElement sourceSymbolElem = QgsSymbolLayerUtils::saveSymbols( sourceSymbols, QStringLiteral( "source-symbol" ), doc, context );
668 rendererElem.appendChild( sourceSymbolElem );
669 }
670
671 // save source color ramp
672 if ( mSourceColorRamp )
673 {
674 QDomElement colorRampElem = QgsSymbolLayerUtils::saveColorRamp( QStringLiteral( "[source]" ), mSourceColorRamp.get(), doc );
675 rendererElem.appendChild( colorRampElem );
676 }
677
678 // save classification method
679 QDomElement classificationMethodElem = mClassificationMethod->save( doc, context );
680 rendererElem.appendChild( classificationMethodElem );
681
682 QDomElement rotationElem = doc.createElement( QStringLiteral( "rotation" ) );
683 rendererElem.appendChild( rotationElem );
684
685 QDomElement sizeScaleElem = doc.createElement( QStringLiteral( "sizescale" ) );
686 rendererElem.appendChild( sizeScaleElem );
687
689 {
690 QDomElement ddsLegendElem = doc.createElement( QStringLiteral( "data-defined-size-legend" ) );
691 mDataDefinedSizeLegend->writeXml( ddsLegendElem, context );
692 rendererElem.appendChild( ddsLegendElem );
693 }
694
695 saveRendererData( doc, rendererElem, context );
696
697 return rendererElem;
698}
699
700QgsLegendSymbolList QgsGraduatedSymbolRenderer::baseLegendSymbolItems() const
701{
703 lst.reserve( mRanges.size() );
704 for ( const QgsRendererRange &range : mRanges )
705 {
706 lst << QgsLegendSymbolItem( range.symbol(), range.label(), range.uuid(), true );
707 }
708 return lst;
709}
710
712QString QgsGraduatedSymbolRenderer::methodIdFromMode( QgsGraduatedSymbolRenderer::Mode mode )
713{
714 switch ( mode )
715 {
716 case EqualInterval:
717 return QStringLiteral( "EqualInterval" );
718 case Quantile:
719 return QStringLiteral( "Quantile" );
720 case Jenks:
721 return QStringLiteral( "Jenks" );
722 case StdDev:
723 return QStringLiteral( "StdDev" );
724 case Pretty:
725 return QStringLiteral( "Pretty" );
726 case Custom:
727 return QString();
728 }
729 return QString();
730}
731
732QgsGraduatedSymbolRenderer::Mode QgsGraduatedSymbolRenderer::modeFromMethodId( const QString &methodId )
733{
734 if ( methodId == QLatin1String( "EqualInterval" ) )
735 return EqualInterval;
736 if ( methodId == QLatin1String( "Quantile" ) )
737 return Quantile;
738 if ( methodId == QLatin1String( "Jenks" ) )
739 return Jenks;
740 if ( methodId == QLatin1String( "StdDev" ) )
741 return StdDev;
742 if ( methodId == QLatin1String( "Pretty" ) )
743 return Pretty;
744 else
745 return Custom;
746}
748
750{
752 {
753 // check that all symbols that have the same size expression
754 QgsProperty ddSize;
755 for ( const QgsRendererRange &range : mRanges )
756 {
757 const QgsMarkerSymbol *symbol = static_cast<const QgsMarkerSymbol *>( range.symbol() );
758 if ( ddSize )
759 {
760 QgsProperty sSize( symbol->dataDefinedSize() );
761 if ( sSize && sSize != ddSize )
762 {
763 // no common size expression
764 return baseLegendSymbolItems();
765 }
766 }
767 else
768 {
769 ddSize = symbol->dataDefinedSize();
770 }
771 }
772
773 if ( ddSize && ddSize.isActive() )
774 {
776
778 ddSizeLegend.updateFromSymbolAndProperty( static_cast<const QgsMarkerSymbol *>( mSourceSymbol.get() ), ddSize );
779 lst += ddSizeLegend.legendSymbolList();
780
781 lst += baseLegendSymbolItems();
782 return lst;
783 }
784 }
785
786 return baseLegendSymbolItems();
787}
788
789QSet< QString > QgsGraduatedSymbolRenderer::legendKeysForFeature( const QgsFeature &feature, QgsRenderContext &context ) const
790{
791 QVariant value = valueForFeature( feature, context );
792
793 // Null values should not be categorized
794 if ( QgsVariantUtils::isNull( value ) )
795 return QSet< QString >();
796
797 // find the right category
798 QString key = legendKeyForValue( value.toDouble() );
799 if ( !key.isNull() )
800 return QSet< QString >() << key;
801 else
802 return QSet< QString >();
803}
804
805QString QgsGraduatedSymbolRenderer::legendKeyToExpression( const QString &key, QgsVectorLayer *layer, bool &ok ) const
806{
807 ok = false;
808 int i = 0;
809 for ( i = 0; i < mRanges.size(); i++ )
810 {
811 if ( mRanges[i].uuid() == key )
812 {
813 ok = true;
814 break;
815 }
816 }
817
818 if ( !ok )
819 {
820 ok = false;
821 return QString();
822 }
823
824 const QString attributeComponent = QgsExpression::quoteFieldExpression( mAttrName, layer );
825 const QgsRendererRange &range = mRanges[i];
826
827 return QStringLiteral( "(%1 >= %2) AND (%1 <= %3)" ).arg( attributeComponent, QgsExpression::quotedValue( range.lowerValue(), QVariant::Double ),
828 QgsExpression::quotedValue( range.upperValue(), QVariant::Double ) );
829}
830
832{
833 return mSourceSymbol.get();
834}
835
837{
838 return mSourceSymbol.get();
839}
840
842{
843 mSourceSymbol.reset( sym );
844}
845
847{
848 return mSourceColorRamp.get();
849}
850
852{
853 return mSourceColorRamp.get();
854}
855
857{
858 if ( ramp == mSourceColorRamp.get() )
859 return;
860
861 mSourceColorRamp.reset( ramp );
862}
863
865{
866 double min = std::numeric_limits<double>::max();
867 for ( int i = 0; i < mRanges.count(); i++ )
868 {
869 double sz = 0;
870 if ( mRanges[i].symbol()->type() == Qgis::SymbolType::Marker )
871 sz = static_cast< QgsMarkerSymbol * >( mRanges[i].symbol() )->size();
872 else if ( mRanges[i].symbol()->type() == Qgis::SymbolType::Line )
873 sz = static_cast< QgsLineSymbol * >( mRanges[i].symbol() )->width();
874 min = std::min( sz, min );
875 }
876 return min;
877}
878
880{
881 double max = std::numeric_limits<double>::min();
882 for ( int i = 0; i < mRanges.count(); i++ )
883 {
884 double sz = 0;
885 if ( mRanges[i].symbol()->type() == Qgis::SymbolType::Marker )
886 sz = static_cast< QgsMarkerSymbol * >( mRanges[i].symbol() )->size();
887 else if ( mRanges[i].symbol()->type() == Qgis::SymbolType::Line )
888 sz = static_cast< QgsLineSymbol * >( mRanges[i].symbol() )->width();
889 max = std::max( sz, max );
890 }
891 return max;
892}
893
894void QgsGraduatedSymbolRenderer::setSymbolSizes( double minSize, double maxSize )
895{
896 for ( int i = 0; i < mRanges.count(); i++ )
897 {
898 std::unique_ptr<QgsSymbol> symbol( mRanges.at( i ).symbol() ? mRanges.at( i ).symbol()->clone() : nullptr );
899 const double size = mRanges.count() > 1
900 ? minSize + i * ( maxSize - minSize ) / ( mRanges.count() - 1 )
901 : .5 * ( maxSize + minSize );
902 if ( symbol->type() == Qgis::SymbolType::Marker )
903 static_cast< QgsMarkerSymbol * >( symbol.get() )->setSize( size );
904 if ( symbol->type() == Qgis::SymbolType::Line )
905 static_cast< QgsLineSymbol * >( symbol.get() )->setWidth( size );
906 updateRangeSymbol( i, symbol.release() );
907 }
908}
909
911{
912 int i = 0;
913 if ( ramp )
914 {
915 setSourceColorRamp( ramp );
916 }
917
918 if ( mSourceColorRamp )
919 {
920 for ( const QgsRendererRange &range : std::as_const( mRanges ) )
921 {
922 QgsSymbol *symbol = range.symbol() ? range.symbol()->clone() : nullptr;
923 if ( symbol )
924 {
925 double colorValue;
926 colorValue = ( mRanges.count() > 1 ? static_cast< double >( i ) / ( mRanges.count() - 1 ) : 0 );
927 symbol->setColor( mSourceColorRamp->color( colorValue ) );
928 }
929 updateRangeSymbol( i, symbol );
930 ++i;
931 }
932 }
933
934}
935
937{
938 if ( !sym )
939 return;
940
941 int i = 0;
942 for ( const QgsRendererRange &range : std::as_const( mRanges ) )
943 {
944 std::unique_ptr<QgsSymbol> symbol( sym->clone() );
945 switch ( mGraduatedMethod )
946 {
948 {
949 symbol->setColor( range.symbol()->color() );
950 break;
951 }
953 {
954 if ( symbol->type() == Qgis::SymbolType::Marker )
955 static_cast<QgsMarkerSymbol *>( symbol.get() )->setSize(
956 static_cast<QgsMarkerSymbol *>( range.symbol() )->size() );
957 else if ( symbol->type() == Qgis::SymbolType::Line )
958 static_cast<QgsLineSymbol *>( symbol.get() )->setWidth(
959 static_cast<QgsLineSymbol *>( range.symbol() )->width() );
960 break;
961 }
962 }
963 updateRangeSymbol( i, symbol.release() );
964 ++i;
965 }
966 setSourceSymbol( sym->clone() );
967}
968
970{
971 return true;
972}
973
975{
976 for ( const QgsRendererRange &range : std::as_const( mRanges ) )
977 {
978 if ( range.uuid() == key )
979 {
980 return range.renderState();
981 }
982 }
983 return true;
984}
985
986void QgsGraduatedSymbolRenderer::checkLegendSymbolItem( const QString &key, bool state )
987{
988 for ( int i = 0; i < mRanges.size(); i++ )
989 {
990 if ( mRanges[i].uuid() == key )
991 {
992 updateRangeRenderState( i, state );
993 break;
994 }
995 }
996}
997
999{
1000 bool ok = false;
1001 int i = 0;
1002 for ( i = 0; i < mRanges.size(); i++ )
1003 {
1004 if ( mRanges[i].uuid() == key )
1005 {
1006 ok = true;
1007 break;
1008 }
1009 }
1010
1011 if ( ok )
1012 updateRangeSymbol( i, symbol );
1013 else
1014 delete symbol;
1015}
1016
1018{
1019 QgsSymbol *newSymbol = symbol->clone();
1020 QString label = QStringLiteral( "0.0 - 0.0" );
1021 mRanges.insert( 0, QgsRendererRange( 0.0, 0.0, newSymbol, label ) );
1022}
1023
1025{
1026 QgsSymbol *newSymbol = mSourceSymbol->clone();
1027 QString label = mClassificationMethod->labelForRange( lower, upper );
1028 mRanges.append( QgsRendererRange( lower, upper, newSymbol, label ) );
1029}
1030
1031void QgsGraduatedSymbolRenderer::addBreak( double breakValue, bool updateSymbols )
1032{
1033 QMutableListIterator< QgsRendererRange > it( mRanges );
1034 while ( it.hasNext() )
1035 {
1036 QgsRendererRange range = it.next();
1037 if ( range.lowerValue() < breakValue && range.upperValue() > breakValue )
1038 {
1040 newRange.setLowerValue( breakValue );
1041 newRange.setUpperValue( range.upperValue() );
1042 newRange.setLabel( mClassificationMethod->labelForRange( newRange ) );
1043 newRange.setSymbol( mSourceSymbol->clone() );
1044
1045 //update old range
1046 bool isDefaultLabel = range.label() == mClassificationMethod->labelForRange( range );
1047 range.setUpperValue( breakValue );
1048 if ( isDefaultLabel )
1049 range.setLabel( mClassificationMethod->labelForRange( range.lowerValue(), breakValue ) );
1050 it.setValue( range );
1051
1052 it.insert( newRange );
1053 break;
1054 }
1055 }
1056
1057 if ( updateSymbols )
1058 {
1059 switch ( mGraduatedMethod )
1060 {
1063 break;
1066 break;
1067 }
1068 }
1069}
1070
1072{
1073 mRanges.append( range );
1074}
1075
1077{
1078 mRanges.removeAt( idx );
1079}
1080
1082{
1083 mRanges.clear();
1084}
1085
1088{
1089 mClassificationMethod->setLabelFormat( labelFormat.format() );
1090 mClassificationMethod->setLabelPrecision( labelFormat.precision() );
1091 mClassificationMethod->setLabelTrimTrailingZeroes( labelFormat.trimTrailingZeroes() );
1092
1093 if ( updateRanges )
1094 {
1096 }
1097}
1099
1101{
1102 for ( int i = 0; i < mRanges.count(); i++ )
1103 {
1105 if ( i == 0 )
1107 else if ( i == mRanges.count() - 1 )
1109 mRanges[i].setLabel( mClassificationMethod->labelForRange( mRanges[i], pos ) );
1110 }
1111}
1112
1114{
1115 // Find the minimum size of a class
1116 double minClassRange = 0.0;
1117 for ( const QgsRendererRange &rendererRange : std::as_const( mRanges ) )
1118 {
1119 double range = rendererRange.upperValue() - rendererRange.lowerValue();
1120 if ( range <= 0.0 )
1121 continue;
1122 if ( minClassRange == 0.0 || range < minClassRange )
1123 minClassRange = range;
1124 }
1125 if ( minClassRange <= 0.0 )
1126 return;
1127
1128 // Now set the number of decimal places to ensure no more than 20% error in
1129 // representing this range (up to 10% at upper and lower end)
1130
1131 int ndp = 10;
1132 double nextDpMinRange = 0.0000000099;
1133 while ( ndp > 0 && nextDpMinRange < minClassRange )
1134 {
1135 ndp--;
1136 nextDpMinRange *= 10.0;
1137 }
1138 mClassificationMethod->setLabelPrecision( ndp );
1139 if ( updateRanges )
1141}
1142
1144{
1145 if ( from < 0 || from >= mRanges.size() || to < 0 || to >= mRanges.size() )
1146 return;
1147 mRanges.move( from, to );
1148}
1149
1151{
1152 return r1 < r2;
1153}
1154
1156{
1157 return !valueLessThan( r1, r2 );
1158}
1159
1161{
1162 if ( order == Qt::AscendingOrder )
1163 {
1164 std::sort( mRanges.begin(), mRanges.end(), valueLessThan );
1165 }
1166 else
1167 {
1168 std::sort( mRanges.begin(), mRanges.end(), valueGreaterThan );
1169 }
1170}
1171
1173{
1174 QgsRangeList sortedRanges = mRanges;
1175 std::sort( sortedRanges.begin(), sortedRanges.end(), valueLessThan );
1176
1177 QgsRangeList::const_iterator it = sortedRanges.constBegin();
1178 if ( it == sortedRanges.constEnd() )
1179 return false;
1180
1181 if ( ( *it ).upperValue() < ( *it ).lowerValue() )
1182 return true;
1183
1184 double prevMax = ( *it ).upperValue();
1185 ++it;
1186
1187 for ( ; it != sortedRanges.constEnd(); ++it )
1188 {
1189 if ( ( *it ).upperValue() < ( *it ).lowerValue() )
1190 return true;
1191
1192 if ( ( *it ).lowerValue() < prevMax )
1193 return true;
1194
1195 prevMax = ( *it ).upperValue();
1196 }
1197 return false;
1198}
1199
1201{
1202 QgsRangeList sortedRanges = mRanges;
1203 std::sort( sortedRanges.begin(), sortedRanges.end(), valueLessThan );
1204
1205 QgsRangeList::const_iterator it = sortedRanges.constBegin();
1206 if ( it == sortedRanges.constEnd() )
1207 return false;
1208
1209 double prevMax = ( *it ).upperValue();
1210 ++it;
1211
1212 for ( ; it != sortedRanges.constEnd(); ++it )
1213 {
1214 if ( !qgsDoubleNear( ( *it ).lowerValue(), prevMax ) )
1215 return true;
1216
1217 prevMax = ( *it ).upperValue();
1218 }
1219 return false;
1220}
1221
1223{
1224 return QString::localeAwareCompare( r1.label(), r2.label() ) < 0;
1225}
1226
1228{
1229 return !labelLessThan( r1, r2 );
1230}
1231
1233{
1234 if ( order == Qt::AscendingOrder )
1235 {
1236 std::sort( mRanges.begin(), mRanges.end(), labelLessThan );
1237 }
1238 else
1239 {
1240 std::sort( mRanges.begin(), mRanges.end(), labelGreaterThan );
1241 }
1242}
1243
1245{
1246 return mClassificationMethod.get();
1247}
1248
1250{
1251 mClassificationMethod.reset( method );
1252}
1253
1255{
1256 QString methodId = methodIdFromMode( mode );
1258 setClassificationMethod( method );
1259}
1260
1262{
1263 mClassificationMethod->setSymmetricMode( useSymmetricMode, mClassificationMethod->symmetryPoint(), mClassificationMethod->symmetryAstride() );
1264}
1265
1267{
1268 mClassificationMethod->setSymmetricMode( mClassificationMethod->symmetricModeEnabled(), symmetryPoint, mClassificationMethod->symmetryAstride() );
1269}
1270
1272{
1273 mClassificationMethod->setSymmetricMode( mClassificationMethod->symmetricModeEnabled(), mClassificationMethod->symmetryPoint(), astride );
1274}
1275
1277{
1278 std::unique_ptr< QgsGraduatedSymbolRenderer > r;
1279 if ( renderer->type() == QLatin1String( "graduatedSymbol" ) )
1280 {
1281 r.reset( static_cast<QgsGraduatedSymbolRenderer *>( renderer->clone() ) );
1282 }
1283 else if ( renderer->type() == QLatin1String( "categorizedSymbol" ) )
1284 {
1285 const QgsCategorizedSymbolRenderer *categorizedSymbolRenderer = dynamic_cast<const QgsCategorizedSymbolRenderer *>( renderer );
1286 if ( categorizedSymbolRenderer )
1287 {
1288 r = std::make_unique< QgsGraduatedSymbolRenderer >( QString(), QgsRangeList() );
1289 if ( categorizedSymbolRenderer->sourceSymbol() )
1290 r->setSourceSymbol( categorizedSymbolRenderer->sourceSymbol()->clone() );
1291 if ( categorizedSymbolRenderer->sourceColorRamp() )
1292 {
1293 bool isRandom = dynamic_cast<const QgsRandomColorRamp *>( categorizedSymbolRenderer->sourceColorRamp() ) ||
1294 dynamic_cast<const QgsLimitedRandomColorRamp *>( categorizedSymbolRenderer->sourceColorRamp() );
1295 if ( !isRandom )
1296 r->setSourceColorRamp( categorizedSymbolRenderer->sourceColorRamp()->clone() );
1297 }
1298 r->setClassAttribute( categorizedSymbolRenderer->classAttribute() );
1299 }
1300 }
1301 else if ( renderer->type() == QLatin1String( "pointDisplacement" ) || renderer->type() == QLatin1String( "pointCluster" ) )
1302 {
1303 const QgsPointDistanceRenderer *pointDistanceRenderer = dynamic_cast<const QgsPointDistanceRenderer *>( renderer );
1304 if ( pointDistanceRenderer )
1305 r.reset( convertFromRenderer( pointDistanceRenderer->embeddedRenderer() ) );
1306 }
1307 else if ( renderer->type() == QLatin1String( "invertedPolygonRenderer" ) )
1308 {
1309 const QgsInvertedPolygonRenderer *invertedPolygonRenderer = dynamic_cast<const QgsInvertedPolygonRenderer *>( renderer );
1310 if ( invertedPolygonRenderer )
1311 r.reset( convertFromRenderer( invertedPolygonRenderer->embeddedRenderer() ) );
1312 }
1313
1314 // If not one of the specifically handled renderers, then just grab the symbol from the renderer
1315 // Could have applied this to specific renderer types (singleSymbol, graduatedSymbol)
1316
1317 if ( !r )
1318 {
1319 r = std::make_unique< QgsGraduatedSymbolRenderer >( QString(), QgsRangeList() );
1320 QgsRenderContext context;
1321 QgsSymbolList symbols = const_cast<QgsFeatureRenderer *>( renderer )->symbols( context );
1322 if ( !symbols.isEmpty() )
1323 {
1324 r->setSourceSymbol( symbols.at( 0 )->clone() );
1325 }
1326 }
1327
1328 renderer->copyRendererData( r.get() );
1329
1330 return r.release();
1331}
1332
1334{
1335 mDataDefinedSizeLegend.reset( settings );
1336}
1337
1339{
1340 return mDataDefinedSizeLegend.get();
1341}
1342
1344{
1345 switch ( method )
1346 {
1348 return QStringLiteral( "GraduatedColor" );
1350 return QStringLiteral( "GraduatedSize" );
1351 }
1352 return QString();
1353}
1354
1355
GraduatedMethod
Methods for modifying symbols by range in a graduated symbol renderer.
Definition: qgis.h:2690
@ Size
Alter size of symbols.
@ Color
Alter color of symbols.
@ Marker
Marker symbol.
@ Line
Line symbol.
static QgsClassificationMethodRegistry * classificationMethodRegistry()
Returns the application's classification methods registry, used in graduated renderer.
A vector of attributes.
Definition: qgsattributes.h:59
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.
QgsClassificationCustom is a dummy implementation of QgsClassification which does not compute any bre...
static const QString METHOD_ID
QgsClassificationEqualInterval is an implementation of QgsClassificationMethod for equal intervals.
QgsClassificationMethod * method(const QString &id)
Returns a new instance of the method for the given id.
QgsClassificationMethod is 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...
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 setLabelTrimTrailingZeroes(bool trimTrailingZeroes)
Defines if the trailing 0 are trimmed in the label.
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.
void setLabelFormat(const QString &format)
Defines the format of the labels for the classes, using %1 and %2 for the bounds.
static QgsClassificationMethod * create(const QDomElement &element, const QgsReadWriteContext &context)
Reads the DOM element and return a new classification method from it.
void setLabelPrecision(int labelPrecision)
Defines the precision for the formatting of the labels.
Abstract base class for color ramps.
Definition: qgscolorramp.h:29
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.
Class for 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.
virtual void stopRender(QgsRenderContext &context)
Must be called when a render cycle has finished, to allow the renderer to clean up.
QString type() const
Definition: qgsrenderer.h:142
void copyRendererData(QgsFeatureRenderer *destRenderer) const
Clones generic renderer data to another renderer.
Definition: qgsrenderer.cpp:46
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.
Definition: qgsrenderer.cpp:90
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:56
QgsAttributes attributes
Definition: qgsfeature.h:65
Container of fields for a vector layer.
Definition: qgsfields.h:45
int lookupField(const QString &fieldName) const
Looks up field's index from the field name.
Definition: qgsfields.cpp:359
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.
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.
QgsInvertedPolygonRenderer is a polygon-only feature renderer used to display features inverted,...
The class stores information about one class/rule of a vector layer renderer in a unified way that ca...
Constrained random color ramp, which returns random colors based on preset parameters.
A line symbol type, for rendering LineString and MultiLineString geometries.
Definition: qgslinesymbol.h:30
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.
Definition: qgsproperty.h:228
bool isActive() const
Returns whether the property is currently active.
Totally random color ramp.
The class is used as a container of context for various read/write operations on other objects.
Contains information about the context of a rendering operation.
double rendererScale() const
Returns the renderer map scale.
QgsExpressionContext & expressionContext()
Gets the expression context.
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:1404
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:1372
static 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, 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:94
void setColor(const QColor &color) const
Sets the color for the symbol.
Definition: qgssymbol.cpp:902
QSet< QString > usedAttributes(const QgsRenderContext &context) const
Returns a list of attributes required to render this feature.
Definition: qgssymbol.cpp:1201
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.
Definition: qgssymbol.cpp:705
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 data sets.
Q_INVOKABLE Qgis::GeometryType geometryType() const
Returns point, line or polygon.
int ANALYSIS_EXPORT lower(int n, int i)
Lower function.
Definition: MathUtils.cpp:337
#define Q_NOWARN_DEPRECATED_POP
Definition: qgis.h:5776
#define Q_NOWARN_DEPRECATED_PUSH
Definition: qgis.h:5775
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)
Definition: qgis.h:5207
#define SIP_DEPRECATED
Definition: qgis_sip.h:106
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:50
QMap< QString, QgsSymbol * > QgsSymbolMap
Definition: qgsrenderer.h:45
QList< QgsSymbol * > QgsSymbolList
Definition: qgsrenderer.h:44
QList< QgsRendererRange > QgsRangeList
int precision
Contains information relating to the style entity currently being visited.