QGIS API Documentation 4.0.0-Norrköping (1ddcee3d0e4)
Loading...
Searching...
No Matches
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
17
18#include <cmath>
19#include <ctime>
20#include <memory>
21
22#include "qgsapplication.h"
23#include "qgsattributes.h"
29#include "qgscolorramp.h"
30#include "qgscolorrampimpl.h"
32#include "qgsexpression.h"
34#include "qgsfeature.h"
36#include "qgslinesymbol.h"
37#include "qgsmarkersymbol.h"
38#include "qgspainteffect.h"
40#include "qgsproperty.h"
41#include "qgssldexportcontext.h"
43#include "qgssymbol.h"
44#include "qgssymbollayer.h"
45#include "qgssymbollayerutils.h"
47#include "qgsvectorlayer.h"
48#include "qgsvectorlayerutils.h"
49
50#include <QDomDocument>
51#include <QDomElement>
52#include <QString>
53
54using namespace Qt::StringLiterals;
55
57 : QgsFeatureRenderer( u"graduatedSymbol"_s )
58 , mAttrName( attrName )
59{
60 // TODO: check ranges for sanity (NULL symbols, invalid ranges)
61
62 //important - we need a deep copy of the ranges list, not a shared copy. This is required because
63 //QgsRendererRange::symbol() is marked const, and so retrieving the symbol via this method does not
64 //trigger a detachment and copy of mRanges BUT that same method CAN be used to modify a symbol in place
65 const auto constRanges = ranges;
66 for ( const QgsRendererRange &range : constRanges )
67 {
68 mRanges << range;
69 }
70
71 mClassificationMethod = std::make_shared<QgsClassificationCustom>();
72}
73
75{
76 mRanges.clear(); // should delete all the symbols
77}
78
80{
82 auto catIt = mRanges.constBegin();
83 for ( ; catIt != mRanges.constEnd(); ++catIt )
84 {
85 if ( QgsSymbol *catSymbol = catIt->symbol() )
86 {
87 if ( catSymbol->flags().testFlag( Qgis::SymbolFlag::AffectsLabeling ) )
89 }
90 }
91
92 return res;
93}
94
96{
97 for ( const QgsRendererRange &range : mRanges )
98 {
99 if ( range.lowerValue() <= value && range.upperValue() >= value )
100 {
101 if ( range.renderState() || mCounting )
102 return &range;
103 else
104 return nullptr;
105 }
106 }
107
108 // second chance -- use a bit of double tolerance to avoid floating point equality fuzziness
109 // if a value falls just outside of a range, but within acceptable double precision tolerance
110 // then we accept it anyway
111 for ( const QgsRendererRange &range : mRanges )
112 {
113 if ( qgsDoubleNear( range.lowerValue(), value ) || qgsDoubleNear( range.upperValue(), value ) )
114 {
115 if ( range.renderState() || mCounting )
116 return &range;
117 else
118 return nullptr;
119 }
120 }
121 // the value is out of the range: return NULL instead of symbol
122 return nullptr;
123}
124
126{
127 if ( const QgsRendererRange *range = rangeForValue( value ) )
128 return range->symbol();
129 return nullptr;
130}
131
133{
134 if ( const QgsRendererRange *matchingRange = rangeForValue( value ) )
135 {
136 for ( const QgsRendererRange &range : mRanges )
137 {
138 if ( matchingRange == &range )
139 return range.uuid();
140 }
141 }
142 return QString();
143}
144
146{
147 return originalSymbolForFeature( feature, context );
148}
149
150QVariant QgsGraduatedSymbolRenderer::valueForFeature( const QgsFeature &feature, QgsRenderContext &context ) const
151{
152 QgsAttributes attrs = feature.attributes();
153 QVariant value;
154 if ( mExpression )
155 {
156 value = mExpression->evaluate( &context.expressionContext() );
157 }
158 else
159 {
160 value = attrs.value( mAttrNum );
161 }
162
163 return value;
164}
165
167{
168 QVariant value = valueForFeature( feature, context );
169
170 // Null values should not be categorized
171 if ( QgsVariantUtils::isNull( value ) )
172 return nullptr;
173
174 // find the right category
175 return symbolForValue( value.toDouble() );
176}
177
179{
180 QgsFeatureRenderer::startRender( context, fields );
181
182 mCounting = context.rendererScale() == 0.0;
183
184 // find out classification attribute index from name
185 mAttrNum = fields.lookupField( mAttrName );
186
187 if ( mAttrNum == -1 )
188 {
189 mExpression = std::make_unique<QgsExpression>( mAttrName );
190 mExpression->prepare( &context.expressionContext() );
191 }
192
193 for ( const QgsRendererRange &range : std::as_const( mRanges ) )
194 {
195 if ( !range.symbol() )
196 continue;
197
198 range.symbol()->startRender( context, fields );
199 }
200}
201
203{
205
206 for ( const QgsRendererRange &range : std::as_const( mRanges ) )
207 {
208 if ( !range.symbol() )
209 continue;
210
211 range.symbol()->stopRender( context );
212 }
213}
214
216{
217 QSet<QString> attributes;
218
219 // mAttrName can contain either attribute name or an expression.
220 // Sometimes it is not possible to distinguish between those two,
221 // e.g. "a - b" can be both a valid attribute name or expression.
222 // Since we do not have access to fields here, try both options.
223 attributes << mAttrName;
224
225 QgsExpression testExpr( mAttrName );
226 if ( !testExpr.hasParserError() )
227 attributes.unite( testExpr.referencedColumns() );
228
229 QgsRangeList::const_iterator range_it = mRanges.constBegin();
230 for ( ; range_it != mRanges.constEnd(); ++range_it )
231 {
232 QgsSymbol *symbol = range_it->symbol();
233 if ( symbol )
234 {
235 attributes.unite( symbol->usedAttributes( context ) );
236 }
237 }
238 return attributes;
239}
240
242{
243 QgsExpression testExpr( mAttrName );
244 if ( !testExpr.hasParserError() )
245 {
246 QgsExpressionContext context;
247 context.appendScopes( QgsExpressionContextUtils::globalProjectLayerScopes( nullptr ) ); // unfortunately no layer access available!
248 testExpr.prepare( &context );
249 return testExpr.needsGeometry();
250 }
251 return false;
252}
253
255{
256 if ( rangeIndex < 0 || rangeIndex >= mRanges.size() )
257 return false;
258 mRanges[rangeIndex].setSymbol( symbol );
259 return true;
260}
261
262bool QgsGraduatedSymbolRenderer::updateRangeLabel( int rangeIndex, const QString &label )
263{
264 if ( rangeIndex < 0 || rangeIndex >= mRanges.size() )
265 return false;
266 mRanges[rangeIndex].setLabel( label );
267 return true;
268}
269
270bool QgsGraduatedSymbolRenderer::updateRangeUpperValue( int rangeIndex, double value )
271{
272 if ( rangeIndex < 0 || rangeIndex >= mRanges.size() )
273 return false;
274 QgsRendererRange &range = mRanges[rangeIndex];
276 if ( rangeIndex == 0 )
278 else if ( rangeIndex == mRanges.count() )
280
281 bool isDefaultLabel = mClassificationMethod->labelForRange( range, pos ) == range.label();
282 range.setUpperValue( value );
283 if ( isDefaultLabel )
284 range.setLabel( mClassificationMethod->labelForRange( range, pos ) );
285
286 return true;
287}
288
289bool QgsGraduatedSymbolRenderer::updateRangeLowerValue( int rangeIndex, double value )
290{
291 if ( rangeIndex < 0 || rangeIndex >= mRanges.size() )
292 return false;
293
294 QgsRendererRange &range = mRanges[rangeIndex];
296 if ( rangeIndex == 0 )
298 else if ( rangeIndex == mRanges.count() )
300
301 bool isDefaultLabel = mClassificationMethod->labelForRange( range, pos ) == range.label();
302 range.setLowerValue( value );
303 if ( isDefaultLabel )
304 range.setLabel( mClassificationMethod->labelForRange( range, pos ) );
305
306 return true;
307}
308
310{
311 if ( rangeIndex < 0 || rangeIndex >= mRanges.size() )
312 return false;
313 mRanges[rangeIndex].setRenderState( value );
314 return true;
315}
316
318{
319 QString s = u"GRADUATED: attr %1\n"_s.arg( mAttrName );
320 for ( int i = 0; i < mRanges.count(); i++ )
321 s += mRanges[i].dump();
322 return s;
323}
324
342
343void QgsGraduatedSymbolRenderer::toSld( QDomDocument &doc, QDomElement &element, const QVariantMap &props ) const
344{
345 QgsSldExportContext context;
346 context.setExtraProperties( props );
347 toSld( doc, element, context );
348}
349
350bool QgsGraduatedSymbolRenderer::toSld( QDomDocument &doc, QDomElement &element, QgsSldExportContext &context ) const
351{
352 const QVariantMap oldProps = context.extraProperties();
353 QVariantMap newProps = oldProps;
354 newProps[u"attribute"_s] = mAttrName;
355 newProps[u"method"_s] = graduatedMethodStr( mGraduatedMethod );
356 context.setExtraProperties( newProps );
357
358 // create a Rule for each range
359 bool first = true;
360 bool result = true;
361 for ( QgsRangeList::const_iterator it = mRanges.constBegin(); it != mRanges.constEnd(); ++it )
362 {
363 if ( !it->toSld( doc, element, mAttrName, context, first ) )
364 result = false;
365 first = false;
366 }
367 context.setExtraProperties( oldProps );
368 return result;
369}
370
372{
373 Q_UNUSED( context )
374 QgsSymbolList lst;
375 lst.reserve( mRanges.count() );
376 for ( const QgsRendererRange &range : std::as_const( mRanges ) )
377 {
378 lst.append( range.symbol() );
379 }
380 return lst;
381}
382
384{
385 for ( const QgsRendererRange &range : std::as_const( mRanges ) )
386 {
387 QgsStyleSymbolEntity entity( range.symbol() );
388 if ( !visitor->visit( QgsStyleEntityVisitorInterface::StyleLeaf( &entity, u"%1 - %2"_s.arg( range.lowerValue() ).arg( range.upperValue() ), range.label() ) ) )
389 return false;
390 }
391
392 if ( mSourceColorRamp )
393 {
395 if ( !visitor->visit( QgsStyleEntityVisitorInterface::StyleLeaf( &entity ) ) )
396 return false;
397 }
398
399 return true;
400}
401
406
407QList<double> QgsGraduatedSymbolRenderer::calcEqualIntervalBreaks( double minimum, double maximum, int classes, bool useSymmetricMode, double symmetryPoint, bool astride )
408{
411 QList<QgsClassificationRange> _classes = method.classes( minimum, maximum, classes );
413}
414
417 QgsVectorLayer *vlayer,
418 const QString &attrName,
419 int classes,
420 Mode mode,
421 QgsSymbol *symbol,
422 QgsColorRamp *ramp,
424 bool useSymmetricMode,
425 double symmetryPoint,
426 const QStringList &listForCboPrettyBreaks,
427 bool astride
428)
429{
430 Q_UNUSED( listForCboPrettyBreaks )
431
433 auto r = std::make_unique< QgsGraduatedSymbolRenderer >( attrName, ranges );
434 r->setSourceSymbol( symbol->clone() );
435 r->setSourceColorRamp( ramp->clone() );
436
437 QString methodId = methodIdFromMode( mode );
438 std::unique_ptr< QgsClassificationMethod > method = QgsApplication::classificationMethodRegistry()->method( methodId );
439
440 if ( method )
441 {
442 method->setSymmetricMode( useSymmetricMode, symmetryPoint, astride );
443 method->setLabelFormat( labelFormat.format() );
444 method->setLabelTrimTrailingZeroes( labelFormat.trimTrailingZeroes() );
445 method->setLabelPrecision( labelFormat.precision() );
446 }
447 r->setClassificationMethod( method.release() );
448
449 QString error;
450 r->updateClasses( vlayer, classes, error );
451 ( void ) error;
452
453 return r.release();
454}
456
458{
459 if ( mAttrName.isEmpty() )
460 return;
461
462 QString methodId = methodIdFromMode( mode );
463 std::unique_ptr< QgsClassificationMethod > method = QgsApplication::classificationMethodRegistry()->method( methodId );
464 method->setSymmetricMode( useSymmetricMode, symmetryPoint, astride );
465 setClassificationMethod( method.release() );
466
467 QString error;
468 updateClasses( vlayer, nclasses, error );
469 ( void ) error;
470}
471
472void QgsGraduatedSymbolRenderer::updateClasses( const QgsVectorLayer *vl, int nclasses, QString &error )
473{
474 Q_UNUSED( error )
476 return;
477
478 QList<QgsClassificationRange> classes = mClassificationMethod->classesV2( vl, mAttrName, nclasses, error );
479
481
482 for ( QList<QgsClassificationRange>::iterator it = classes.begin(); it != classes.end(); ++it )
483 {
485 addClass( QgsRendererRange( *it, newSymbol ) );
486 }
487 updateColorRamp( nullptr );
488}
489
496
498{
499 QDomElement symbolsElem = element.firstChildElement( u"symbols"_s );
500 if ( symbolsElem.isNull() )
501 return nullptr;
502
503 QDomElement rangesElem = element.firstChildElement( u"ranges"_s );
504 if ( rangesElem.isNull() )
505 return nullptr;
506
507 QgsSymbolMap symbolMap = QgsSymbolLayerUtils::loadSymbols( symbolsElem, context );
509
510 QDomElement rangeElem = rangesElem.firstChildElement();
511 int i = 0;
512 QSet<QString> usedUuids;
513 while ( !rangeElem.isNull() )
514 {
515 if ( rangeElem.tagName() == "range"_L1 )
516 {
517 double lowerValue = rangeElem.attribute( u"lower"_s ).toDouble();
518 double upperValue = rangeElem.attribute( u"upper"_s ).toDouble();
519 QString symbolName = rangeElem.attribute( u"symbol"_s );
520 QString label = context.projectTranslator()->translate( u"project:layers:%1:legendsymbollabels"_s.arg( context.currentLayerId() ), rangeElem.attribute( u"label"_s ) );
521 QgsDebugMsgLevel( "context" + u"project:layers:%1:legendsymbollabels"_s.arg( context.currentLayerId() ) + " source " + rangeElem.attribute( u"label"_s ), 3 );
522
523 bool render = rangeElem.attribute( u"render"_s, u"true"_s ) != "false"_L1;
524 QString uuid = rangeElem.attribute( u"uuid"_s, QString::number( i++ ) );
525 while ( usedUuids.contains( uuid ) )
526 {
527 uuid = QUuid::createUuid().toString();
528 }
529 if ( symbolMap.contains( symbolName ) )
530 {
531 QgsSymbol *symbol = symbolMap.take( symbolName );
532 ranges.append( QgsRendererRange( lowerValue, upperValue, symbol, label, render, uuid ) );
533 usedUuids << uuid;
534 }
535 }
536 rangeElem = rangeElem.nextSiblingElement();
537 }
538
539 QString attrName = element.attribute( u"attr"_s );
540
541 auto r = std::make_unique< QgsGraduatedSymbolRenderer >( attrName, ranges );
542
543 QString attrMethod = element.attribute( u"graduatedMethod"_s );
544 if ( !attrMethod.isEmpty() )
545 {
547 r->setGraduatedMethod( Qgis::GraduatedMethod::Color );
548 else if ( attrMethod == graduatedMethodStr( Qgis::GraduatedMethod::Size ) )
549 r->setGraduatedMethod( Qgis::GraduatedMethod::Size );
550 }
551
552
553 // delete symbols if there are any more
555
556 // try to load source symbol (optional)
557 QDomElement sourceSymbolElem = element.firstChildElement( u"source-symbol"_s );
558 if ( !sourceSymbolElem.isNull() )
559 {
560 QgsSymbolMap sourceSymbolMap = QgsSymbolLayerUtils::loadSymbols( sourceSymbolElem, context );
561 if ( sourceSymbolMap.contains( u"0"_s ) )
562 {
563 r->setSourceSymbol( sourceSymbolMap.take( u"0"_s ) );
564 }
565 QgsSymbolLayerUtils::clearSymbolMap( sourceSymbolMap );
566 }
567
568 // try to load color ramp (optional)
569 QDomElement sourceColorRampElem = element.firstChildElement( u"colorramp"_s );
570 if ( !sourceColorRampElem.isNull() && sourceColorRampElem.attribute( u"name"_s ) == "[source]"_L1 )
571 {
572 r->setSourceColorRamp( QgsSymbolLayerUtils::loadColorRamp( sourceColorRampElem ).release() );
573 }
574
575 // try to load mode
576
577 QDomElement modeElem = element.firstChildElement( u"mode"_s ); // old format, backward compatibility
578 QDomElement methodElem = element.firstChildElement( u"classificationMethod"_s );
579 std::unique_ptr< QgsClassificationMethod > method;
580
581 // TODO QGIS 5 Remove
582 // backward compatibility for QGIS project < 3.10
583 if ( !modeElem.isNull() )
584 {
585 QString modeString = modeElem.attribute( u"name"_s );
586 QString methodId;
587 // the strings saved in the project does not match with the old Mode enum
588 if ( modeString == "equal"_L1 )
589 methodId = u"EqualInterval"_s;
590 else if ( modeString == "quantile"_L1 )
591 methodId = u"Quantile"_s;
592 else if ( modeString == "jenks"_L1 )
593 methodId = u"Jenks"_s;
594 else if ( modeString == "stddev"_L1 )
595 methodId = u"StdDev"_s;
596 else if ( modeString == "pretty"_L1 )
597 methodId = u"Pretty"_s;
598
600
601 // symmetric mode
602 QDomElement symmetricModeElem = element.firstChildElement( u"symmetricMode"_s );
603 if ( !symmetricModeElem.isNull() )
604 {
605 // symmetry
606 QString symmetricEnabled = symmetricModeElem.attribute( u"enabled"_s );
607 QString symmetricPointString = symmetricModeElem.attribute( u"symmetryPoint"_s );
608 QString astrideEnabled = symmetricModeElem.attribute( u"astride"_s );
609 method->setSymmetricMode( symmetricEnabled == "true"_L1, symmetricPointString.toDouble(), astrideEnabled == "true"_L1 );
610 }
611 QDomElement labelFormatElem = element.firstChildElement( u"labelformat"_s );
612 if ( !labelFormatElem.isNull() )
613 {
614 // label format
615 QString format = labelFormatElem.attribute( u"format"_s, "%1" + u" - "_s + "%2" );
616 int precision = labelFormatElem.attribute( u"decimalplaces"_s, u"4"_s ).toInt();
617 bool trimTrailingZeroes = labelFormatElem.attribute( u"trimtrailingzeroes"_s, u"false"_s ) == "true"_L1;
618 method->setLabelFormat( format );
619 method->setLabelPrecision( precision );
620 method->setLabelTrimTrailingZeroes( trimTrailingZeroes );
621 }
622 // End of backward compatibility
623 }
624 else
625 {
626 // QGIS project 3.10+
627 method = QgsClassificationMethod::create( methodElem, context );
628 }
629
630 // apply the method
631 r->setClassificationMethod( method.release() );
632
633 QDomElement rotationElem = element.firstChildElement( u"rotation"_s );
634 if ( !rotationElem.isNull() && !rotationElem.attribute( u"field"_s ).isEmpty() )
635 {
636 for ( const QgsRendererRange &range : std::as_const( r->mRanges ) )
637 {
638 convertSymbolRotation( range.symbol(), rotationElem.attribute( u"field"_s ) );
639 }
640 if ( r->mSourceSymbol )
641 {
642 convertSymbolRotation( r->mSourceSymbol.get(), rotationElem.attribute( u"field"_s ) );
643 }
644 }
645 QDomElement sizeScaleElem = element.firstChildElement( u"sizescale"_s );
646 if ( !sizeScaleElem.isNull() && !sizeScaleElem.attribute( u"field"_s ).isEmpty() )
647 {
648 for ( const QgsRendererRange &range : std::as_const( r->mRanges ) )
649 {
650 convertSymbolSizeScale( range.symbol(), QgsSymbolLayerUtils::decodeScaleMethod( sizeScaleElem.attribute( u"scalemethod"_s ) ), sizeScaleElem.attribute( u"field"_s ) );
651 }
652 if ( r->mSourceSymbol && r->mSourceSymbol->type() == Qgis::SymbolType::Marker )
653 {
654 convertSymbolSizeScale( r->mSourceSymbol.get(), QgsSymbolLayerUtils::decodeScaleMethod( sizeScaleElem.attribute( u"scalemethod"_s ) ), sizeScaleElem.attribute( u"field"_s ) );
655 }
656 }
657
658 QDomElement ddsLegendSizeElem = element.firstChildElement( u"data-defined-size-legend"_s );
659 if ( !ddsLegendSizeElem.isNull() )
660 {
661 r->mDataDefinedSizeLegend.reset( QgsDataDefinedSizeLegend::readXml( ddsLegendSizeElem, context ) );
662 }
663 // TODO: symbol levels
664 return r.release();
665}
666
667QDomElement QgsGraduatedSymbolRenderer::save( QDomDocument &doc, const QgsReadWriteContext &context )
668{
669 QDomElement rendererElem = doc.createElement( RENDERER_TAG_NAME );
670 rendererElem.setAttribute( u"type"_s, u"graduatedSymbol"_s );
671 rendererElem.setAttribute( u"attr"_s, mAttrName );
672 rendererElem.setAttribute( u"graduatedMethod"_s, graduatedMethodStr( mGraduatedMethod ) );
673
674 // ranges
675 int i = 0;
677 QDomElement rangesElem = doc.createElement( u"ranges"_s );
678 QgsRangeList::const_iterator it = mRanges.constBegin();
679 for ( ; it != mRanges.constEnd(); ++it )
680 {
681 const QgsRendererRange &range = *it;
682 QString symbolName = QString::number( i );
683 symbols.insert( symbolName, range.symbol() );
684
685 QDomElement rangeElem = doc.createElement( u"range"_s );
686 rangeElem.setAttribute( u"lower"_s, QString::number( range.lowerValue(), 'f', 15 ) );
687 rangeElem.setAttribute( u"upper"_s, QString::number( range.upperValue(), 'f', 15 ) );
688 rangeElem.setAttribute( u"symbol"_s, symbolName );
689 rangeElem.setAttribute( u"label"_s, range.label() );
690 rangeElem.setAttribute( u"render"_s, range.renderState() ? u"true"_s : u"false"_s );
691 rangeElem.setAttribute( u"uuid"_s, range.uuid() );
692 rangesElem.appendChild( rangeElem );
693 i++;
694 }
695
696 rendererElem.appendChild( rangesElem );
697
698 // save symbols
699 QDomElement symbolsElem = QgsSymbolLayerUtils::saveSymbols( symbols, u"symbols"_s, doc, context );
700 rendererElem.appendChild( symbolsElem );
701
702 // save source symbol
703 if ( mSourceSymbol )
704 {
705 QgsSymbolMap sourceSymbols;
706 sourceSymbols.insert( u"0"_s, mSourceSymbol.get() );
707 QDomElement sourceSymbolElem = QgsSymbolLayerUtils::saveSymbols( sourceSymbols, u"source-symbol"_s, doc, context );
708 rendererElem.appendChild( sourceSymbolElem );
709 }
710
711 // save source color ramp
712 if ( mSourceColorRamp )
713 {
714 QDomElement colorRampElem = QgsSymbolLayerUtils::saveColorRamp( u"[source]"_s, mSourceColorRamp.get(), doc );
715 rendererElem.appendChild( colorRampElem );
716 }
717
718 // save classification method
719 QDomElement classificationMethodElem = mClassificationMethod->save( doc, context );
720 rendererElem.appendChild( classificationMethodElem );
721
722 QDomElement rotationElem = doc.createElement( u"rotation"_s );
723 rendererElem.appendChild( rotationElem );
724
725 QDomElement sizeScaleElem = doc.createElement( u"sizescale"_s );
726 rendererElem.appendChild( sizeScaleElem );
727
729 {
730 QDomElement ddsLegendElem = doc.createElement( u"data-defined-size-legend"_s );
731 mDataDefinedSizeLegend->writeXml( ddsLegendElem, context );
732 rendererElem.appendChild( ddsLegendElem );
733 }
734
735 saveRendererData( doc, rendererElem, context );
736
737 return rendererElem;
738}
739
740QgsLegendSymbolList QgsGraduatedSymbolRenderer::baseLegendSymbolItems() const
741{
743 lst.reserve( mRanges.size() );
744 for ( const QgsRendererRange &range : mRanges )
745 {
746 lst << QgsLegendSymbolItem( range.symbol(), range.label(), range.uuid(), true );
747 }
748 return lst;
749}
750
752QString QgsGraduatedSymbolRenderer::methodIdFromMode( QgsGraduatedSymbolRenderer::Mode mode )
753{
754 switch ( mode )
755 {
756 case EqualInterval:
757 return u"EqualInterval"_s;
758 case Quantile:
759 return u"Quantile"_s;
760 case Jenks:
761 return u"Jenks"_s;
762 case StdDev:
763 return u"StdDev"_s;
764 case Pretty:
765 return u"Pretty"_s;
766 case Custom:
767 return QString();
768 }
769 return QString();
770}
771
772QgsGraduatedSymbolRenderer::Mode QgsGraduatedSymbolRenderer::modeFromMethodId( const QString &methodId )
773{
774 if ( methodId == "EqualInterval"_L1 )
775 return EqualInterval;
776 if ( methodId == "Quantile"_L1 )
777 return Quantile;
778 if ( methodId == "Jenks"_L1 )
779 return Jenks;
780 if ( methodId == "StdDev"_L1 )
781 return StdDev;
782 if ( methodId == "Pretty"_L1 )
783 return Pretty;
784 else
785 return Custom;
786}
788
790{
792 {
793 // check that all symbols that have the same size expression
794 QgsProperty ddSize;
795 for ( const QgsRendererRange &range : mRanges )
796 {
797 const QgsMarkerSymbol *symbol = static_cast<const QgsMarkerSymbol *>( range.symbol() );
798 if ( ddSize )
799 {
800 QgsProperty sSize( symbol->dataDefinedSize() );
801 if ( sSize && sSize != ddSize )
802 {
803 // no common size expression
804 return baseLegendSymbolItems();
805 }
806 }
807 else
808 {
809 ddSize = symbol->dataDefinedSize();
810 }
811 }
812
813 if ( ddSize && ddSize.isActive() )
814 {
816
818 ddSizeLegend.updateFromSymbolAndProperty( static_cast<const QgsMarkerSymbol *>( mSourceSymbol.get() ), ddSize );
819 lst += ddSizeLegend.legendSymbolList();
820
821 lst += baseLegendSymbolItems();
822 return lst;
823 }
824 }
825
826 return baseLegendSymbolItems();
827}
828
829QSet< QString > QgsGraduatedSymbolRenderer::legendKeysForFeature( const QgsFeature &feature, QgsRenderContext &context ) const
830{
831 QVariant value = valueForFeature( feature, context );
832
833 // Null values should not be categorized
834 if ( QgsVariantUtils::isNull( value ) )
835 return QSet< QString >();
836
837 // find the right category
838 QString key = legendKeyForValue( value.toDouble() );
839 if ( !key.isNull() )
840 return QSet< QString >() << key;
841 else
842 return QSet< QString >();
843}
844
845QString QgsGraduatedSymbolRenderer::legendKeyToExpression( const QString &key, QgsVectorLayer *layer, bool &ok ) const
846{
847 ok = false;
848 int i = 0;
849 for ( i = 0; i < mRanges.size(); i++ )
850 {
851 if ( mRanges[i].uuid() == key )
852 {
853 ok = true;
854 break;
855 }
856 }
857
858 if ( !ok )
859 {
860 ok = false;
861 return QString();
862 }
863
864 const QString attributeComponent = QgsExpression::quoteFieldExpression( mAttrName, layer );
865 const QgsRendererRange &range = mRanges[i];
866
867 return u"(%1 >= %2) AND (%1 <= %3)"_s
868 .arg( attributeComponent, QgsExpression::quotedValue( range.lowerValue(), QMetaType::Type::Double ), QgsExpression::quotedValue( range.upperValue(), QMetaType::Type::Double ) );
869}
870
875
877{
878 return mSourceSymbol.get();
879}
880
885
890
895
897{
898 if ( ramp == mSourceColorRamp.get() )
899 return;
900
901 mSourceColorRamp.reset( ramp );
902}
903
905{
906 double min = std::numeric_limits<double>::max();
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 min = std::min( sz, min );
915 }
916 return min;
917}
918
920{
921 double max = std::numeric_limits<double>::min();
922 for ( int i = 0; i < mRanges.count(); i++ )
923 {
924 double sz = 0;
925 if ( mRanges[i].symbol()->type() == Qgis::SymbolType::Marker )
926 sz = static_cast< QgsMarkerSymbol * >( mRanges[i].symbol() )->size();
927 else if ( mRanges[i].symbol()->type() == Qgis::SymbolType::Line )
928 sz = static_cast< QgsLineSymbol * >( mRanges[i].symbol() )->width();
929 max = std::max( sz, max );
930 }
931 return max;
932}
933
934void QgsGraduatedSymbolRenderer::setSymbolSizes( double minSize, double maxSize )
935{
936 for ( int i = 0; i < mRanges.count(); i++ )
937 {
938 std::unique_ptr<QgsSymbol> symbol( mRanges.at( i ).symbol() ? mRanges.at( i ).symbol()->clone() : nullptr );
939 const double size = mRanges.count() > 1 ? minSize + i * ( maxSize - minSize ) / ( mRanges.count() - 1 ) : .5 * ( maxSize + minSize );
940 if ( symbol )
941 {
942 switch ( symbol->type() )
943 {
945 static_cast< QgsMarkerSymbol * >( symbol.get() )->setSize( size );
946 break;
948 static_cast< QgsLineSymbol * >( symbol.get() )->setWidth( size );
949 break;
952 break;
953 }
954 updateRangeSymbol( i, symbol.release() );
955 }
956 }
957}
958
960{
961 int i = 0;
962 if ( ramp )
963 {
964 setSourceColorRamp( ramp );
965 }
966
967 if ( mSourceColorRamp )
968 {
969 for ( const QgsRendererRange &range : std::as_const( mRanges ) )
970 {
971 QgsSymbol *symbol = range.symbol() ? range.symbol()->clone() : nullptr;
972 if ( symbol )
973 {
974 double colorValue;
975 colorValue = ( mRanges.count() > 1 ? static_cast< double >( i ) / ( mRanges.count() - 1 ) : 0 );
976 symbol->setColor( mSourceColorRamp->color( colorValue ) );
977 }
978 updateRangeSymbol( i, symbol );
979 ++i;
980 }
981 }
982}
983
985{
986 if ( !sym )
987 return;
988
989 int i = 0;
990 for ( const QgsRendererRange &range : std::as_const( mRanges ) )
991 {
992 std::unique_ptr<QgsSymbol> symbol( sym->clone() );
993 switch ( mGraduatedMethod )
994 {
996 {
997 symbol->setColor( range.symbol()->color() );
998 break;
999 }
1001 {
1002 if ( symbol->type() == Qgis::SymbolType::Marker )
1003 static_cast<QgsMarkerSymbol *>( symbol.get() )->setSize( static_cast<QgsMarkerSymbol *>( range.symbol() )->size() );
1004 else if ( symbol->type() == Qgis::SymbolType::Line )
1005 static_cast<QgsLineSymbol *>( symbol.get() )->setWidth( static_cast<QgsLineSymbol *>( range.symbol() )->width() );
1006 break;
1007 }
1008 }
1009 updateRangeSymbol( i, symbol.release() );
1010 ++i;
1011 }
1012 setSourceSymbol( sym->clone() );
1013}
1014
1016{
1017 return true;
1018}
1019
1021{
1022 for ( const QgsRendererRange &range : std::as_const( mRanges ) )
1023 {
1024 if ( range.uuid() == key )
1025 {
1026 return range.renderState();
1027 }
1028 }
1029 return true;
1030}
1031
1032void QgsGraduatedSymbolRenderer::checkLegendSymbolItem( const QString &key, bool state )
1033{
1034 for ( int i = 0; i < mRanges.size(); i++ )
1035 {
1036 if ( mRanges[i].uuid() == key )
1037 {
1038 updateRangeRenderState( i, state );
1039 break;
1040 }
1041 }
1042}
1043
1045{
1046 bool ok = false;
1047 int i = 0;
1048 for ( i = 0; i < mRanges.size(); i++ )
1049 {
1050 if ( mRanges[i].uuid() == key )
1051 {
1052 ok = true;
1053 break;
1054 }
1055 }
1056
1057 if ( ok )
1058 updateRangeSymbol( i, symbol );
1059 else
1060 delete symbol;
1061}
1062
1064{
1065 QgsSymbol *newSymbol = symbol->clone();
1066 QString label = u"0.0 - 0.0"_s;
1067 mRanges.insert( 0, QgsRendererRange( 0.0, 0.0, newSymbol, label ) );
1068}
1069
1070void QgsGraduatedSymbolRenderer::addClass( double lower, double upper )
1071{
1072 QgsSymbol *newSymbol = mSourceSymbol->clone();
1073 QString label = mClassificationMethod->labelForRange( lower, upper );
1074 mRanges.append( QgsRendererRange( lower, upper, newSymbol, label ) );
1075}
1076
1078{
1079 QMutableListIterator< QgsRendererRange > it( mRanges );
1080 while ( it.hasNext() )
1081 {
1082 QgsRendererRange range = it.next();
1083 if ( range.lowerValue() < breakValue && range.upperValue() > breakValue )
1084 {
1086 newRange.setLowerValue( breakValue );
1087 newRange.setUpperValue( range.upperValue() );
1088 newRange.setLabel( mClassificationMethod->labelForRange( newRange ) );
1089 newRange.setSymbol( mSourceSymbol->clone() );
1090
1091 //update old range
1092 bool isDefaultLabel = range.label() == mClassificationMethod->labelForRange( range );
1093 range.setUpperValue( breakValue );
1094 if ( isDefaultLabel )
1095 range.setLabel( mClassificationMethod->labelForRange( range.lowerValue(), breakValue ) );
1096 it.setValue( range );
1097
1098 it.insert( newRange );
1099 break;
1100 }
1101 }
1102
1103 if ( updateSymbols )
1104 {
1105 switch ( mGraduatedMethod )
1106 {
1109 break;
1112 break;
1113 }
1114 }
1115}
1116
1118{
1119 mRanges.append( range );
1120}
1121
1123{
1124 mRanges.removeAt( idx );
1125}
1126
1131
1134{
1135 mClassificationMethod->setLabelFormat( labelFormat.format() );
1136 mClassificationMethod->setLabelPrecision( labelFormat.precision() );
1137 mClassificationMethod->setLabelTrimTrailingZeroes( labelFormat.trimTrailingZeroes() );
1138
1139 if ( updateRanges )
1140 {
1142 }
1143}
1145
1147{
1148 for ( int i = 0; i < mRanges.count(); i++ )
1149 {
1151 if ( i == 0 )
1153 else if ( i == mRanges.count() - 1 )
1155 mRanges[i].setLabel( mClassificationMethod->labelForRange( mRanges[i], pos ) );
1156 }
1157}
1158
1160{
1161 // Find the minimum size of a class
1162 double minClassRange = 0.0;
1163 for ( const QgsRendererRange &rendererRange : std::as_const( mRanges ) )
1164 {
1165 double range = rendererRange.upperValue() - rendererRange.lowerValue();
1166 if ( range <= 0.0 )
1167 continue;
1168 if ( minClassRange == 0.0 || range < minClassRange )
1169 minClassRange = range;
1170 }
1171 if ( minClassRange <= 0.0 )
1172 return;
1173
1174 // Now set the number of decimal places to ensure no more than 20% error in
1175 // representing this range (up to 10% at upper and lower end)
1176
1177 int ndp = 10;
1178 double nextDpMinRange = 0.0000000099;
1179 while ( ndp > 0 && nextDpMinRange < minClassRange )
1180 {
1181 ndp--;
1182 nextDpMinRange *= 10.0;
1183 }
1184 mClassificationMethod->setLabelPrecision( ndp );
1185 if ( updateRanges )
1187}
1188
1190{
1191 if ( from < 0 || from >= mRanges.size() || to < 0 || to >= mRanges.size() )
1192 return;
1193 mRanges.move( from, to );
1194}
1195
1197{
1198 return r1 < r2;
1199}
1200
1202{
1203 return !valueLessThan( r1, r2 );
1204}
1205
1207{
1208 if ( order == Qt::AscendingOrder )
1209 {
1210 std::sort( mRanges.begin(), mRanges.end(), valueLessThan );
1211 }
1212 else
1213 {
1214 std::sort( mRanges.begin(), mRanges.end(), valueGreaterThan );
1215 }
1216}
1217
1219{
1220 QgsRangeList sortedRanges = mRanges;
1221 std::sort( sortedRanges.begin(), sortedRanges.end(), valueLessThan );
1222
1223 QgsRangeList::const_iterator it = sortedRanges.constBegin();
1224 if ( it == sortedRanges.constEnd() )
1225 return false;
1226
1227 if ( ( *it ).upperValue() < ( *it ).lowerValue() )
1228 return true;
1229
1230 double prevMax = ( *it ).upperValue();
1231 ++it;
1232
1233 for ( ; it != sortedRanges.constEnd(); ++it )
1234 {
1235 if ( ( *it ).upperValue() < ( *it ).lowerValue() )
1236 return true;
1237
1238 if ( ( *it ).lowerValue() < prevMax )
1239 return true;
1240
1241 prevMax = ( *it ).upperValue();
1242 }
1243 return false;
1244}
1245
1247{
1248 QgsRangeList sortedRanges = mRanges;
1249 std::sort( sortedRanges.begin(), sortedRanges.end(), valueLessThan );
1250
1251 QgsRangeList::const_iterator it = sortedRanges.constBegin();
1252 if ( it == sortedRanges.constEnd() )
1253 return false;
1254
1255 double prevMax = ( *it ).upperValue();
1256 ++it;
1257
1258 for ( ; it != sortedRanges.constEnd(); ++it )
1259 {
1260 if ( !qgsDoubleNear( ( *it ).lowerValue(), prevMax ) )
1261 return true;
1262
1263 prevMax = ( *it ).upperValue();
1264 }
1265 return false;
1266}
1267
1269{
1270 return QString::localeAwareCompare( r1.label(), r2.label() ) < 0;
1271}
1272
1274{
1275 return !labelLessThan( r1, r2 );
1276}
1277
1279{
1280 if ( order == Qt::AscendingOrder )
1281 {
1282 std::sort( mRanges.begin(), mRanges.end(), labelLessThan );
1283 }
1284 else
1285 {
1286 std::sort( mRanges.begin(), mRanges.end(), labelGreaterThan );
1287 }
1288}
1289
1294
1299
1301{
1302 QString methodId = methodIdFromMode( mode );
1303 std::unique_ptr< QgsClassificationMethod > method = QgsApplication::classificationMethodRegistry()->method( methodId );
1304 setClassificationMethod( method.release() );
1305}
1306
1311
1313{
1314 mClassificationMethod->setSymmetricMode( mClassificationMethod->symmetricModeEnabled(), symmetryPoint, mClassificationMethod->symmetryAstride() );
1315}
1316
1318{
1319 mClassificationMethod->setSymmetricMode( mClassificationMethod->symmetricModeEnabled(), mClassificationMethod->symmetryPoint(), astride );
1320}
1321
1323{
1324 std::unique_ptr< QgsGraduatedSymbolRenderer > r;
1325 if ( renderer->type() == "graduatedSymbol"_L1 )
1326 {
1327 r.reset( static_cast<QgsGraduatedSymbolRenderer *>( renderer->clone() ) );
1328 }
1329 else if ( renderer->type() == "categorizedSymbol"_L1 )
1330 {
1331 const QgsCategorizedSymbolRenderer *categorizedSymbolRenderer = dynamic_cast<const QgsCategorizedSymbolRenderer *>( renderer );
1332 if ( categorizedSymbolRenderer )
1333 {
1334 r = std::make_unique< QgsGraduatedSymbolRenderer >( QString(), QgsRangeList() );
1335 if ( categorizedSymbolRenderer->sourceSymbol() )
1336 r->setSourceSymbol( categorizedSymbolRenderer->sourceSymbol()->clone() );
1337 if ( categorizedSymbolRenderer->sourceColorRamp() )
1338 {
1339 bool isRandom = dynamic_cast<const QgsRandomColorRamp *>( categorizedSymbolRenderer->sourceColorRamp() )
1340 || dynamic_cast<const QgsLimitedRandomColorRamp *>( categorizedSymbolRenderer->sourceColorRamp() );
1341 if ( !isRandom )
1342 r->setSourceColorRamp( categorizedSymbolRenderer->sourceColorRamp()->clone() );
1343 }
1344 r->setClassAttribute( categorizedSymbolRenderer->classAttribute() );
1345 }
1346 }
1347 else if ( renderer->type() == "pointDisplacement"_L1 || renderer->type() == "pointCluster"_L1 )
1348 {
1349 const QgsPointDistanceRenderer *pointDistanceRenderer = dynamic_cast<const QgsPointDistanceRenderer *>( renderer );
1350 if ( pointDistanceRenderer )
1351 r.reset( convertFromRenderer( pointDistanceRenderer->embeddedRenderer() ) );
1352 }
1353 else if ( renderer->type() == "invertedPolygonRenderer"_L1 )
1354 {
1355 const QgsInvertedPolygonRenderer *invertedPolygonRenderer = dynamic_cast<const QgsInvertedPolygonRenderer *>( renderer );
1356 if ( invertedPolygonRenderer )
1357 r.reset( convertFromRenderer( invertedPolygonRenderer->embeddedRenderer() ) );
1358 }
1359
1360 // If not one of the specifically handled renderers, then just grab the symbol from the renderer
1361 // Could have applied this to specific renderer types (singleSymbol, graduatedSymbol)
1362
1363 if ( !r )
1364 {
1365 r = std::make_unique< QgsGraduatedSymbolRenderer >( QString(), QgsRangeList() );
1366 QgsRenderContext context;
1367 QgsSymbolList symbols = const_cast<QgsFeatureRenderer *>( renderer )->symbols( context );
1368 if ( !symbols.isEmpty() )
1369 {
1370 r->setSourceSymbol( symbols.at( 0 )->clone() );
1371 }
1372 }
1373
1374 renderer->copyRendererData( r.get() );
1375
1376 return r.release();
1377}
1378
1383
1388
1390{
1391 switch ( method )
1392 {
1394 return u"GraduatedColor"_s;
1396 return u"GraduatedSize"_s;
1397 }
1398 return QString();
1399}
QFlags< FeatureRendererFlag > FeatureRendererFlags
Flags controlling behavior of vector feature renderers.
Definition qgis.h:864
GraduatedMethod
Methods for modifying symbols by range in a graduated symbol renderer.
Definition qgis.h:3420
@ Size
Alter size of symbols.
Definition qgis.h:3422
@ Color
Alter color of symbols.
Definition qgis.h:3421
@ AffectsLabeling
If present, indicates that the renderer will participate in the map labeling problem.
Definition qgis.h:855
@ Marker
Marker symbol.
Definition qgis.h:637
@ Line
Line symbol.
Definition qgis.h:638
@ Fill
Fill symbol.
Definition qgis.h:639
@ Hybrid
Hybrid symbol.
Definition qgis.h:640
@ AffectsLabeling
If present, indicates that the symbol will participate in the map labeling problem.
Definition qgis.h:875
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 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.
QgsFeatureRenderer(const QString &type)
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)
Converts old rotation expressions to symbol level data defined angles.
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)
Converts old sizeScale expressions to symbol level data defined sizes.
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:60
QgsAttributes attributes
Definition qgsfeature.h:69
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.
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)
void addClass(QgsSymbol *symbol)
Adds a class to the renderer, with the specified symbol.
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)
Q_DECL_DEPRECATED 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.
void setWidth(double width) const
Sets the width for the whole line symbol.
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.
void setSize(double size) const
Sets the size for the whole symbol.
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.
virtual QString translate(const QString &context, const QString &sourceText, const char *disambiguation=nullptr, int n=-1) const =0
Translates a string using the Qt QTranslator mechanism.
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.
const QgsProjectTranslator * projectTranslator() const
Returns the project translator.
const QString currentLayerId() const
Returns the currently used layer id as string.
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.
Holds SLD export options and other information related to SLD export of a QGIS layer style.
void setExtraProperties(const QVariantMap &properties)
Sets the open ended set of properties that can drive/inform the SLD encoding.
QVariantMap extraProperties() const
Returns the open ended set of properties that can drive/inform the SLD encoding.
A color ramp entity for QgsStyle databases.
Definition qgsstyle.h:1422
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:1393
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:227
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:7504
#define Q_NOWARN_DEPRECATED_PUSH
Definition qgis.h:7503
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference).
Definition qgis.h:6975
#define SIP_DEPRECATED
Definition qgis_sip.h:113
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 QgsDebugMsgLevel(str, level)
Definition qgslogger.h:63
#define RENDERER_TAG_NAME
Definition qgsrenderer.h:57
QMap< QString, QgsSymbol * > QgsSymbolMap
Definition qgsrenderer.h:52
QList< QgsSymbol * > QgsSymbolList
Definition qgsrenderer.h:51
QList< QgsRendererRange > QgsRangeList
Contains information relating to the style entity currently being visited.