QGIS API Documentation 3.99.0-Master (d270888f95f)
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 bool useSymmetricMode, double symmetryPoint, bool astride )
459{
460 if ( mAttrName.isEmpty() )
461 return;
462
463 QString methodId = methodIdFromMode( mode );
464 std::unique_ptr< QgsClassificationMethod > method = QgsApplication::classificationMethodRegistry()->method( methodId );
465 method->setSymmetricMode( useSymmetricMode, symmetryPoint, astride );
466 setClassificationMethod( method.release() );
467
468 QString error;
469 updateClasses( vlayer, nclasses, error );
470 ( void )error;
471}
472
473void QgsGraduatedSymbolRenderer::updateClasses( const QgsVectorLayer *vl, int nclasses, QString &error )
474{
475 Q_UNUSED( error )
477 return;
478
479 QList<QgsClassificationRange> classes = mClassificationMethod->classesV2( vl, mAttrName, nclasses, error );
480
482
483 for ( QList<QgsClassificationRange>::iterator it = classes.begin(); it != classes.end(); ++it )
484 {
486 addClass( QgsRendererRange( *it, newSymbol ) );
487 }
488 updateColorRamp( nullptr );
489}
490
497
499{
500 QDomElement symbolsElem = element.firstChildElement( u"symbols"_s );
501 if ( symbolsElem.isNull() )
502 return nullptr;
503
504 QDomElement rangesElem = element.firstChildElement( u"ranges"_s );
505 if ( rangesElem.isNull() )
506 return nullptr;
507
508 QgsSymbolMap symbolMap = QgsSymbolLayerUtils::loadSymbols( symbolsElem, context );
510
511 QDomElement rangeElem = rangesElem.firstChildElement();
512 int i = 0;
513 QSet<QString> usedUuids;
514 while ( !rangeElem.isNull() )
515 {
516 if ( rangeElem.tagName() == "range"_L1 )
517 {
518 double lowerValue = rangeElem.attribute( u"lower"_s ).toDouble();
519 double upperValue = rangeElem.attribute( u"upper"_s ).toDouble();
520 QString symbolName = rangeElem.attribute( u"symbol"_s );
521 QString label = context.projectTranslator()->translate( u"project:layers:%1:legendsymbollabels"_s.arg( context.currentLayerId() ), rangeElem.attribute( u"label"_s ) );
522 QgsDebugMsgLevel( "context" + u"project:layers:%1:legendsymbollabels"_s.arg( context.currentLayerId() ) + " source " + rangeElem.attribute( u"label"_s ), 3 );
523
524 bool render = rangeElem.attribute( u"render"_s, u"true"_s ) != "false"_L1;
525 QString uuid = rangeElem.attribute( u"uuid"_s, QString::number( i++ ) );
526 while ( usedUuids.contains( uuid ) )
527 {
528 uuid = QUuid::createUuid().toString();
529 }
530 if ( symbolMap.contains( symbolName ) )
531 {
532 QgsSymbol *symbol = symbolMap.take( symbolName );
533 ranges.append( QgsRendererRange( lowerValue, upperValue, symbol, label, render, uuid ) );
534 usedUuids << uuid;
535 }
536 }
537 rangeElem = rangeElem.nextSiblingElement();
538 }
539
540 QString attrName = element.attribute( u"attr"_s );
541
542 auto r = std::make_unique< QgsGraduatedSymbolRenderer >( attrName, ranges );
543
544 QString attrMethod = element.attribute( u"graduatedMethod"_s );
545 if ( !attrMethod.isEmpty() )
546 {
548 r->setGraduatedMethod( Qgis::GraduatedMethod::Color );
549 else if ( attrMethod == graduatedMethodStr( Qgis::GraduatedMethod::Size ) )
550 r->setGraduatedMethod( Qgis::GraduatedMethod::Size );
551 }
552
553
554 // delete symbols if there are any more
556
557 // try to load source symbol (optional)
558 QDomElement sourceSymbolElem = element.firstChildElement( u"source-symbol"_s );
559 if ( !sourceSymbolElem.isNull() )
560 {
561 QgsSymbolMap sourceSymbolMap = QgsSymbolLayerUtils::loadSymbols( sourceSymbolElem, context );
562 if ( sourceSymbolMap.contains( u"0"_s ) )
563 {
564 r->setSourceSymbol( sourceSymbolMap.take( u"0"_s ) );
565 }
566 QgsSymbolLayerUtils::clearSymbolMap( sourceSymbolMap );
567 }
568
569 // try to load color ramp (optional)
570 QDomElement sourceColorRampElem = element.firstChildElement( u"colorramp"_s );
571 if ( !sourceColorRampElem.isNull() && sourceColorRampElem.attribute( u"name"_s ) == "[source]"_L1 )
572 {
573 r->setSourceColorRamp( QgsSymbolLayerUtils::loadColorRamp( sourceColorRampElem ).release() );
574 }
575
576 // try to load mode
577
578 QDomElement modeElem = element.firstChildElement( u"mode"_s ); // old format, backward compatibility
579 QDomElement methodElem = element.firstChildElement( u"classificationMethod"_s );
580 std::unique_ptr< QgsClassificationMethod > method;
581
582 // TODO QGIS 5 Remove
583 // backward compatibility for QGIS project < 3.10
584 if ( !modeElem.isNull() )
585 {
586 QString modeString = modeElem.attribute( u"name"_s );
587 QString methodId;
588 // the strings saved in the project does not match with the old Mode enum
589 if ( modeString == "equal"_L1 )
590 methodId = u"EqualInterval"_s;
591 else if ( modeString == "quantile"_L1 )
592 methodId = u"Quantile"_s;
593 else if ( modeString == "jenks"_L1 )
594 methodId = u"Jenks"_s;
595 else if ( modeString == "stddev"_L1 )
596 methodId = u"StdDev"_s;
597 else if ( modeString == "pretty"_L1 )
598 methodId = u"Pretty"_s;
599
601
602 // symmetric mode
603 QDomElement symmetricModeElem = element.firstChildElement( u"symmetricMode"_s );
604 if ( !symmetricModeElem.isNull() )
605 {
606 // symmetry
607 QString symmetricEnabled = symmetricModeElem.attribute( u"enabled"_s );
608 QString symmetricPointString = symmetricModeElem.attribute( u"symmetryPoint"_s );
609 QString astrideEnabled = symmetricModeElem.attribute( u"astride"_s );
610 method->setSymmetricMode( symmetricEnabled == "true"_L1, symmetricPointString.toDouble(), astrideEnabled == "true"_L1 );
611 }
612 QDomElement labelFormatElem = element.firstChildElement( u"labelformat"_s );
613 if ( !labelFormatElem.isNull() )
614 {
615 // label format
616 QString format = labelFormatElem.attribute( u"format"_s, "%1" + u" - "_s + "%2" );
617 int precision = labelFormatElem.attribute( u"decimalplaces"_s, u"4"_s ).toInt();
618 bool trimTrailingZeroes = labelFormatElem.attribute( u"trimtrailingzeroes"_s, u"false"_s ) == "true"_L1;
619 method->setLabelFormat( format );
620 method->setLabelPrecision( precision );
621 method->setLabelTrimTrailingZeroes( trimTrailingZeroes );
622 }
623 // End of backward compatibility
624 }
625 else
626 {
627 // QGIS project 3.10+
628 method = QgsClassificationMethod::create( methodElem, context );
629 }
630
631 // apply the method
632 r->setClassificationMethod( method.release() );
633
634 QDomElement rotationElem = element.firstChildElement( u"rotation"_s );
635 if ( !rotationElem.isNull() && !rotationElem.attribute( u"field"_s ).isEmpty() )
636 {
637 for ( const QgsRendererRange &range : std::as_const( r->mRanges ) )
638 {
639 convertSymbolRotation( range.symbol(), rotationElem.attribute( u"field"_s ) );
640 }
641 if ( r->mSourceSymbol )
642 {
643 convertSymbolRotation( r->mSourceSymbol.get(), rotationElem.attribute( u"field"_s ) );
644 }
645 }
646 QDomElement sizeScaleElem = element.firstChildElement( u"sizescale"_s );
647 if ( !sizeScaleElem.isNull() && !sizeScaleElem.attribute( u"field"_s ).isEmpty() )
648 {
649 for ( const QgsRendererRange &range : std::as_const( r->mRanges ) )
650 {
651 convertSymbolSizeScale( range.symbol(),
652 QgsSymbolLayerUtils::decodeScaleMethod( sizeScaleElem.attribute( u"scalemethod"_s ) ),
653 sizeScaleElem.attribute( u"field"_s ) );
654 }
655 if ( r->mSourceSymbol && r->mSourceSymbol->type() == Qgis::SymbolType::Marker )
656 {
657 convertSymbolSizeScale( r->mSourceSymbol.get(),
658 QgsSymbolLayerUtils::decodeScaleMethod( sizeScaleElem.attribute( u"scalemethod"_s ) ),
659 sizeScaleElem.attribute( u"field"_s ) );
660 }
661 }
662
663 QDomElement ddsLegendSizeElem = element.firstChildElement( u"data-defined-size-legend"_s );
664 if ( !ddsLegendSizeElem.isNull() )
665 {
666 r->mDataDefinedSizeLegend.reset( QgsDataDefinedSizeLegend::readXml( ddsLegendSizeElem, context ) );
667 }
668// TODO: symbol levels
669 return r.release();
670}
671
672QDomElement QgsGraduatedSymbolRenderer::save( QDomDocument &doc, const QgsReadWriteContext &context )
673{
674 QDomElement rendererElem = doc.createElement( RENDERER_TAG_NAME );
675 rendererElem.setAttribute( u"type"_s, u"graduatedSymbol"_s );
676 rendererElem.setAttribute( u"attr"_s, mAttrName );
677 rendererElem.setAttribute( u"graduatedMethod"_s, graduatedMethodStr( mGraduatedMethod ) );
678
679 // ranges
680 int i = 0;
682 QDomElement rangesElem = doc.createElement( u"ranges"_s );
683 QgsRangeList::const_iterator it = mRanges.constBegin();
684 for ( ; it != mRanges.constEnd(); ++it )
685 {
686 const QgsRendererRange &range = *it;
687 QString symbolName = QString::number( i );
688 symbols.insert( symbolName, range.symbol() );
689
690 QDomElement rangeElem = doc.createElement( u"range"_s );
691 rangeElem.setAttribute( u"lower"_s, QString::number( range.lowerValue(), 'f', 15 ) );
692 rangeElem.setAttribute( u"upper"_s, QString::number( range.upperValue(), 'f', 15 ) );
693 rangeElem.setAttribute( u"symbol"_s, symbolName );
694 rangeElem.setAttribute( u"label"_s, range.label() );
695 rangeElem.setAttribute( u"render"_s, range.renderState() ? u"true"_s : u"false"_s );
696 rangeElem.setAttribute( u"uuid"_s, range.uuid() );
697 rangesElem.appendChild( rangeElem );
698 i++;
699 }
700
701 rendererElem.appendChild( rangesElem );
702
703 // save symbols
704 QDomElement symbolsElem = QgsSymbolLayerUtils::saveSymbols( symbols, u"symbols"_s, doc, context );
705 rendererElem.appendChild( symbolsElem );
706
707 // save source symbol
708 if ( mSourceSymbol )
709 {
710 QgsSymbolMap sourceSymbols;
711 sourceSymbols.insert( u"0"_s, mSourceSymbol.get() );
712 QDomElement sourceSymbolElem = QgsSymbolLayerUtils::saveSymbols( sourceSymbols, u"source-symbol"_s, doc, context );
713 rendererElem.appendChild( sourceSymbolElem );
714 }
715
716 // save source color ramp
717 if ( mSourceColorRamp )
718 {
719 QDomElement colorRampElem = QgsSymbolLayerUtils::saveColorRamp( u"[source]"_s, mSourceColorRamp.get(), doc );
720 rendererElem.appendChild( colorRampElem );
721 }
722
723 // save classification method
724 QDomElement classificationMethodElem = mClassificationMethod->save( doc, context );
725 rendererElem.appendChild( classificationMethodElem );
726
727 QDomElement rotationElem = doc.createElement( u"rotation"_s );
728 rendererElem.appendChild( rotationElem );
729
730 QDomElement sizeScaleElem = doc.createElement( u"sizescale"_s );
731 rendererElem.appendChild( sizeScaleElem );
732
734 {
735 QDomElement ddsLegendElem = doc.createElement( u"data-defined-size-legend"_s );
736 mDataDefinedSizeLegend->writeXml( ddsLegendElem, context );
737 rendererElem.appendChild( ddsLegendElem );
738 }
739
740 saveRendererData( doc, rendererElem, context );
741
742 return rendererElem;
743}
744
745QgsLegendSymbolList QgsGraduatedSymbolRenderer::baseLegendSymbolItems() const
746{
748 lst.reserve( mRanges.size() );
749 for ( const QgsRendererRange &range : mRanges )
750 {
751 lst << QgsLegendSymbolItem( range.symbol(), range.label(), range.uuid(), true );
752 }
753 return lst;
754}
755
757QString QgsGraduatedSymbolRenderer::methodIdFromMode( QgsGraduatedSymbolRenderer::Mode mode )
758{
759 switch ( mode )
760 {
761 case EqualInterval:
762 return u"EqualInterval"_s;
763 case Quantile:
764 return u"Quantile"_s;
765 case Jenks:
766 return u"Jenks"_s;
767 case StdDev:
768 return u"StdDev"_s;
769 case Pretty:
770 return u"Pretty"_s;
771 case Custom:
772 return QString();
773 }
774 return QString();
775}
776
777QgsGraduatedSymbolRenderer::Mode QgsGraduatedSymbolRenderer::modeFromMethodId( const QString &methodId )
778{
779 if ( methodId == "EqualInterval"_L1 )
780 return EqualInterval;
781 if ( methodId == "Quantile"_L1 )
782 return Quantile;
783 if ( methodId == "Jenks"_L1 )
784 return Jenks;
785 if ( methodId == "StdDev"_L1 )
786 return StdDev;
787 if ( methodId == "Pretty"_L1 )
788 return Pretty;
789 else
790 return Custom;
791}
793
795{
797 {
798 // check that all symbols that have the same size expression
799 QgsProperty ddSize;
800 for ( const QgsRendererRange &range : mRanges )
801 {
802 const QgsMarkerSymbol *symbol = static_cast<const QgsMarkerSymbol *>( range.symbol() );
803 if ( ddSize )
804 {
805 QgsProperty sSize( symbol->dataDefinedSize() );
806 if ( sSize && sSize != ddSize )
807 {
808 // no common size expression
809 return baseLegendSymbolItems();
810 }
811 }
812 else
813 {
814 ddSize = symbol->dataDefinedSize();
815 }
816 }
817
818 if ( ddSize && ddSize.isActive() )
819 {
821
823 ddSizeLegend.updateFromSymbolAndProperty( static_cast<const QgsMarkerSymbol *>( mSourceSymbol.get() ), ddSize );
824 lst += ddSizeLegend.legendSymbolList();
825
826 lst += baseLegendSymbolItems();
827 return lst;
828 }
829 }
830
831 return baseLegendSymbolItems();
832}
833
834QSet< QString > QgsGraduatedSymbolRenderer::legendKeysForFeature( const QgsFeature &feature, QgsRenderContext &context ) const
835{
836 QVariant value = valueForFeature( feature, context );
837
838 // Null values should not be categorized
839 if ( QgsVariantUtils::isNull( value ) )
840 return QSet< QString >();
841
842 // find the right category
843 QString key = legendKeyForValue( value.toDouble() );
844 if ( !key.isNull() )
845 return QSet< QString >() << key;
846 else
847 return QSet< QString >();
848}
849
850QString QgsGraduatedSymbolRenderer::legendKeyToExpression( const QString &key, QgsVectorLayer *layer, bool &ok ) const
851{
852 ok = false;
853 int i = 0;
854 for ( i = 0; i < mRanges.size(); i++ )
855 {
856 if ( mRanges[i].uuid() == key )
857 {
858 ok = true;
859 break;
860 }
861 }
862
863 if ( !ok )
864 {
865 ok = false;
866 return QString();
867 }
868
869 const QString attributeComponent = QgsExpression::quoteFieldExpression( mAttrName, layer );
870 const QgsRendererRange &range = mRanges[i];
871
872 return u"(%1 >= %2) AND (%1 <= %3)"_s.arg( attributeComponent, QgsExpression::quotedValue( range.lowerValue(), QMetaType::Type::Double ),
873 QgsExpression::quotedValue( range.upperValue(), QMetaType::Type::Double ) );
874}
875
880
882{
883 return mSourceSymbol.get();
884}
885
890
895
900
902{
903 if ( ramp == mSourceColorRamp.get() )
904 return;
905
906 mSourceColorRamp.reset( ramp );
907}
908
910{
911 double min = std::numeric_limits<double>::max();
912 for ( int i = 0; i < mRanges.count(); i++ )
913 {
914 double sz = 0;
915 if ( mRanges[i].symbol()->type() == Qgis::SymbolType::Marker )
916 sz = static_cast< QgsMarkerSymbol * >( mRanges[i].symbol() )->size();
917 else if ( mRanges[i].symbol()->type() == Qgis::SymbolType::Line )
918 sz = static_cast< QgsLineSymbol * >( mRanges[i].symbol() )->width();
919 min = std::min( sz, min );
920 }
921 return min;
922}
923
925{
926 double max = std::numeric_limits<double>::min();
927 for ( int i = 0; i < mRanges.count(); i++ )
928 {
929 double sz = 0;
930 if ( mRanges[i].symbol()->type() == Qgis::SymbolType::Marker )
931 sz = static_cast< QgsMarkerSymbol * >( mRanges[i].symbol() )->size();
932 else if ( mRanges[i].symbol()->type() == Qgis::SymbolType::Line )
933 sz = static_cast< QgsLineSymbol * >( mRanges[i].symbol() )->width();
934 max = std::max( sz, max );
935 }
936 return max;
937}
938
939void QgsGraduatedSymbolRenderer::setSymbolSizes( double minSize, double maxSize )
940{
941 for ( int i = 0; i < mRanges.count(); i++ )
942 {
943 std::unique_ptr<QgsSymbol> symbol( mRanges.at( i ).symbol() ? mRanges.at( i ).symbol()->clone() : nullptr );
944 const double size = mRanges.count() > 1
945 ? minSize + i * ( maxSize - minSize ) / ( mRanges.count() - 1 )
946 : .5 * ( maxSize + minSize );
947 if ( symbol )
948 {
949 switch ( symbol->type() )
950 {
952 static_cast< QgsMarkerSymbol * >( symbol.get() )->setSize( size );
953 break;
955 static_cast< QgsLineSymbol * >( symbol.get() )->setWidth( size );
956 break;
959 break;
960 }
961 updateRangeSymbol( i, symbol.release() );
962 }
963 }
964}
965
967{
968 int i = 0;
969 if ( ramp )
970 {
971 setSourceColorRamp( ramp );
972 }
973
974 if ( mSourceColorRamp )
975 {
976 for ( const QgsRendererRange &range : std::as_const( mRanges ) )
977 {
978 QgsSymbol *symbol = range.symbol() ? range.symbol()->clone() : nullptr;
979 if ( symbol )
980 {
981 double colorValue;
982 colorValue = ( mRanges.count() > 1 ? static_cast< double >( i ) / ( mRanges.count() - 1 ) : 0 );
983 symbol->setColor( mSourceColorRamp->color( colorValue ) );
984 }
985 updateRangeSymbol( i, symbol );
986 ++i;
987 }
988 }
989
990}
991
993{
994 if ( !sym )
995 return;
996
997 int i = 0;
998 for ( const QgsRendererRange &range : std::as_const( mRanges ) )
999 {
1000 std::unique_ptr<QgsSymbol> symbol( sym->clone() );
1001 switch ( mGraduatedMethod )
1002 {
1004 {
1005 symbol->setColor( range.symbol()->color() );
1006 break;
1007 }
1009 {
1010 if ( symbol->type() == Qgis::SymbolType::Marker )
1011 static_cast<QgsMarkerSymbol *>( symbol.get() )->setSize(
1012 static_cast<QgsMarkerSymbol *>( range.symbol() )->size() );
1013 else if ( symbol->type() == Qgis::SymbolType::Line )
1014 static_cast<QgsLineSymbol *>( symbol.get() )->setWidth(
1015 static_cast<QgsLineSymbol *>( range.symbol() )->width() );
1016 break;
1017 }
1018 }
1019 updateRangeSymbol( i, symbol.release() );
1020 ++i;
1021 }
1022 setSourceSymbol( sym->clone() );
1023}
1024
1026{
1027 return true;
1028}
1029
1031{
1032 for ( const QgsRendererRange &range : std::as_const( mRanges ) )
1033 {
1034 if ( range.uuid() == key )
1035 {
1036 return range.renderState();
1037 }
1038 }
1039 return true;
1040}
1041
1042void QgsGraduatedSymbolRenderer::checkLegendSymbolItem( const QString &key, bool state )
1043{
1044 for ( int i = 0; i < mRanges.size(); i++ )
1045 {
1046 if ( mRanges[i].uuid() == key )
1047 {
1048 updateRangeRenderState( i, state );
1049 break;
1050 }
1051 }
1052}
1053
1055{
1056 bool ok = false;
1057 int i = 0;
1058 for ( i = 0; i < mRanges.size(); i++ )
1059 {
1060 if ( mRanges[i].uuid() == key )
1061 {
1062 ok = true;
1063 break;
1064 }
1065 }
1066
1067 if ( ok )
1068 updateRangeSymbol( i, symbol );
1069 else
1070 delete symbol;
1071}
1072
1074{
1075 QgsSymbol *newSymbol = symbol->clone();
1076 QString label = u"0.0 - 0.0"_s;
1077 mRanges.insert( 0, QgsRendererRange( 0.0, 0.0, newSymbol, label ) );
1078}
1079
1080void QgsGraduatedSymbolRenderer::addClass( double lower, double upper )
1081{
1082 QgsSymbol *newSymbol = mSourceSymbol->clone();
1083 QString label = mClassificationMethod->labelForRange( lower, upper );
1084 mRanges.append( QgsRendererRange( lower, upper, newSymbol, label ) );
1085}
1086
1088{
1089 QMutableListIterator< QgsRendererRange > it( mRanges );
1090 while ( it.hasNext() )
1091 {
1092 QgsRendererRange range = it.next();
1093 if ( range.lowerValue() < breakValue && range.upperValue() > breakValue )
1094 {
1096 newRange.setLowerValue( breakValue );
1097 newRange.setUpperValue( range.upperValue() );
1098 newRange.setLabel( mClassificationMethod->labelForRange( newRange ) );
1099 newRange.setSymbol( mSourceSymbol->clone() );
1100
1101 //update old range
1102 bool isDefaultLabel = range.label() == mClassificationMethod->labelForRange( range );
1103 range.setUpperValue( breakValue );
1104 if ( isDefaultLabel )
1105 range.setLabel( mClassificationMethod->labelForRange( range.lowerValue(), breakValue ) );
1106 it.setValue( range );
1107
1108 it.insert( newRange );
1109 break;
1110 }
1111 }
1112
1113 if ( updateSymbols )
1114 {
1115 switch ( mGraduatedMethod )
1116 {
1119 break;
1122 break;
1123 }
1124 }
1125}
1126
1128{
1129 mRanges.append( range );
1130}
1131
1133{
1134 mRanges.removeAt( idx );
1135}
1136
1141
1144{
1145 mClassificationMethod->setLabelFormat( labelFormat.format() );
1146 mClassificationMethod->setLabelPrecision( labelFormat.precision() );
1147 mClassificationMethod->setLabelTrimTrailingZeroes( labelFormat.trimTrailingZeroes() );
1148
1149 if ( updateRanges )
1150 {
1152 }
1153}
1155
1157{
1158 for ( int i = 0; i < mRanges.count(); i++ )
1159 {
1161 if ( i == 0 )
1163 else if ( i == mRanges.count() - 1 )
1165 mRanges[i].setLabel( mClassificationMethod->labelForRange( mRanges[i], pos ) );
1166 }
1167}
1168
1170{
1171 // Find the minimum size of a class
1172 double minClassRange = 0.0;
1173 for ( const QgsRendererRange &rendererRange : std::as_const( mRanges ) )
1174 {
1175 double range = rendererRange.upperValue() - rendererRange.lowerValue();
1176 if ( range <= 0.0 )
1177 continue;
1178 if ( minClassRange == 0.0 || range < minClassRange )
1179 minClassRange = range;
1180 }
1181 if ( minClassRange <= 0.0 )
1182 return;
1183
1184 // Now set the number of decimal places to ensure no more than 20% error in
1185 // representing this range (up to 10% at upper and lower end)
1186
1187 int ndp = 10;
1188 double nextDpMinRange = 0.0000000099;
1189 while ( ndp > 0 && nextDpMinRange < minClassRange )
1190 {
1191 ndp--;
1192 nextDpMinRange *= 10.0;
1193 }
1194 mClassificationMethod->setLabelPrecision( ndp );
1195 if ( updateRanges )
1197}
1198
1200{
1201 if ( from < 0 || from >= mRanges.size() || to < 0 || to >= mRanges.size() )
1202 return;
1203 mRanges.move( from, to );
1204}
1205
1207{
1208 return r1 < r2;
1209}
1210
1212{
1213 return !valueLessThan( r1, r2 );
1214}
1215
1217{
1218 if ( order == Qt::AscendingOrder )
1219 {
1220 std::sort( mRanges.begin(), mRanges.end(), valueLessThan );
1221 }
1222 else
1223 {
1224 std::sort( mRanges.begin(), mRanges.end(), valueGreaterThan );
1225 }
1226}
1227
1229{
1230 QgsRangeList sortedRanges = mRanges;
1231 std::sort( sortedRanges.begin(), sortedRanges.end(), valueLessThan );
1232
1233 QgsRangeList::const_iterator it = sortedRanges.constBegin();
1234 if ( it == sortedRanges.constEnd() )
1235 return false;
1236
1237 if ( ( *it ).upperValue() < ( *it ).lowerValue() )
1238 return true;
1239
1240 double prevMax = ( *it ).upperValue();
1241 ++it;
1242
1243 for ( ; it != sortedRanges.constEnd(); ++it )
1244 {
1245 if ( ( *it ).upperValue() < ( *it ).lowerValue() )
1246 return true;
1247
1248 if ( ( *it ).lowerValue() < prevMax )
1249 return true;
1250
1251 prevMax = ( *it ).upperValue();
1252 }
1253 return false;
1254}
1255
1257{
1258 QgsRangeList sortedRanges = mRanges;
1259 std::sort( sortedRanges.begin(), sortedRanges.end(), valueLessThan );
1260
1261 QgsRangeList::const_iterator it = sortedRanges.constBegin();
1262 if ( it == sortedRanges.constEnd() )
1263 return false;
1264
1265 double prevMax = ( *it ).upperValue();
1266 ++it;
1267
1268 for ( ; it != sortedRanges.constEnd(); ++it )
1269 {
1270 if ( !qgsDoubleNear( ( *it ).lowerValue(), prevMax ) )
1271 return true;
1272
1273 prevMax = ( *it ).upperValue();
1274 }
1275 return false;
1276}
1277
1279{
1280 return QString::localeAwareCompare( r1.label(), r2.label() ) < 0;
1281}
1282
1284{
1285 return !labelLessThan( r1, r2 );
1286}
1287
1289{
1290 if ( order == Qt::AscendingOrder )
1291 {
1292 std::sort( mRanges.begin(), mRanges.end(), labelLessThan );
1293 }
1294 else
1295 {
1296 std::sort( mRanges.begin(), mRanges.end(), labelGreaterThan );
1297 }
1298}
1299
1304
1309
1311{
1312 QString methodId = methodIdFromMode( mode );
1313 std::unique_ptr< QgsClassificationMethod > method = QgsApplication::classificationMethodRegistry()->method( methodId );
1314 setClassificationMethod( method.release() );
1315}
1316
1321
1323{
1324 mClassificationMethod->setSymmetricMode( mClassificationMethod->symmetricModeEnabled(), symmetryPoint, mClassificationMethod->symmetryAstride() );
1325}
1326
1328{
1329 mClassificationMethod->setSymmetricMode( mClassificationMethod->symmetricModeEnabled(), mClassificationMethod->symmetryPoint(), astride );
1330}
1331
1333{
1334 std::unique_ptr< QgsGraduatedSymbolRenderer > r;
1335 if ( renderer->type() == "graduatedSymbol"_L1 )
1336 {
1337 r.reset( static_cast<QgsGraduatedSymbolRenderer *>( renderer->clone() ) );
1338 }
1339 else if ( renderer->type() == "categorizedSymbol"_L1 )
1340 {
1341 const QgsCategorizedSymbolRenderer *categorizedSymbolRenderer = dynamic_cast<const QgsCategorizedSymbolRenderer *>( renderer );
1342 if ( categorizedSymbolRenderer )
1343 {
1344 r = std::make_unique< QgsGraduatedSymbolRenderer >( QString(), QgsRangeList() );
1345 if ( categorizedSymbolRenderer->sourceSymbol() )
1346 r->setSourceSymbol( categorizedSymbolRenderer->sourceSymbol()->clone() );
1347 if ( categorizedSymbolRenderer->sourceColorRamp() )
1348 {
1349 bool isRandom = dynamic_cast<const QgsRandomColorRamp *>( categorizedSymbolRenderer->sourceColorRamp() ) ||
1350 dynamic_cast<const QgsLimitedRandomColorRamp *>( categorizedSymbolRenderer->sourceColorRamp() );
1351 if ( !isRandom )
1352 r->setSourceColorRamp( categorizedSymbolRenderer->sourceColorRamp()->clone() );
1353 }
1354 r->setClassAttribute( categorizedSymbolRenderer->classAttribute() );
1355 }
1356 }
1357 else if ( renderer->type() == "pointDisplacement"_L1 || renderer->type() == "pointCluster"_L1 )
1358 {
1359 const QgsPointDistanceRenderer *pointDistanceRenderer = dynamic_cast<const QgsPointDistanceRenderer *>( renderer );
1360 if ( pointDistanceRenderer )
1361 r.reset( convertFromRenderer( pointDistanceRenderer->embeddedRenderer() ) );
1362 }
1363 else if ( renderer->type() == "invertedPolygonRenderer"_L1 )
1364 {
1365 const QgsInvertedPolygonRenderer *invertedPolygonRenderer = dynamic_cast<const QgsInvertedPolygonRenderer *>( renderer );
1366 if ( invertedPolygonRenderer )
1367 r.reset( convertFromRenderer( invertedPolygonRenderer->embeddedRenderer() ) );
1368 }
1369
1370 // If not one of the specifically handled renderers, then just grab the symbol from the renderer
1371 // Could have applied this to specific renderer types (singleSymbol, graduatedSymbol)
1372
1373 if ( !r )
1374 {
1375 r = std::make_unique< QgsGraduatedSymbolRenderer >( QString(), QgsRangeList() );
1376 QgsRenderContext context;
1377 QgsSymbolList symbols = const_cast<QgsFeatureRenderer *>( renderer )->symbols( context );
1378 if ( !symbols.isEmpty() )
1379 {
1380 r->setSourceSymbol( symbols.at( 0 )->clone() );
1381 }
1382 }
1383
1384 renderer->copyRendererData( r.get() );
1385
1386 return r.release();
1387}
1388
1393
1398
1400{
1401 switch ( method )
1402 {
1404 return u"GraduatedColor"_s;
1406 return u"GraduatedSize"_s;
1407 }
1408 return QString();
1409}
1410
1411
QFlags< FeatureRendererFlag > FeatureRendererFlags
Flags controlling behavior of vector feature renderers.
Definition qgis.h:857
GraduatedMethod
Methods for modifying symbols by range in a graduated symbol renderer.
Definition qgis.h:3365
@ Size
Alter size of symbols.
Definition qgis.h:3367
@ Color
Alter color of symbols.
Definition qgis.h:3366
@ AffectsLabeling
If present, indicates that the renderer will participate in the map labeling problem.
Definition qgis.h:848
@ Marker
Marker symbol.
Definition qgis.h:630
@ Line
Line symbol.
Definition qgis.h:631
@ Fill
Fill symbol.
Definition qgis.h:632
@ Hybrid
Hybrid symbol.
Definition qgis.h:633
@ AffectsLabeling
If present, indicates that the symbol will participate in the map labeling problem.
Definition qgis.h:868
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:1430
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:1398
static std::unique_ptr< QgsColorRamp > loadColorRamp(QDomElement &element)
Creates a color ramp from the settings encoded in an XML element.
static Qgis::ScaleMethod decodeScaleMethod(const QString &str)
Decodes a symbol scale method from a string.
static QDomElement saveColorRamp(const QString &name, const QgsColorRamp *ramp, QDomDocument &doc)
Encodes a color ramp's settings to an XML element.
static void clearSymbolMap(QgsSymbolMap &symbols)
static QgsSymbolMap loadSymbols(QDomElement &element, const QgsReadWriteContext &context)
Reads a collection of symbols from XML and returns them in a map. Caller is responsible for deleting ...
static QDomElement saveSymbols(QgsSymbolMap &symbols, const QString &tagName, QDomDocument &doc, const QgsReadWriteContext &context)
Writes a collection of symbols to XML with specified tagName for the top-level element.
Abstract base class for all rendered symbols.
Definition qgssymbol.h:231
void setColor(const QColor &color) const
Sets the color for the symbol.
QSet< QString > usedAttributes(const QgsRenderContext &context) const
Returns a list of attributes required to render this feature.
virtual QgsSymbol * clone() const =0
Returns a deep copy of this symbol.
static QgsSymbol * defaultSymbol(Qgis::GeometryType geomType)
Returns a new default symbol for the specified geometry type.
static bool isNull(const QVariant &variant, bool silenceNullWarnings=false)
Returns true if the specified variant should be considered a NULL value.
Represents a vector layer which manages a vector based dataset.
Q_INVOKABLE Qgis::GeometryType geometryType() const
Returns point, line or polygon.
#define Q_NOWARN_DEPRECATED_POP
Definition qgis.h:7451
#define Q_NOWARN_DEPRECATED_PUSH
Definition qgis.h:7450
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference).
Definition qgis.h:6900
#define SIP_DEPRECATED
Definition qgis_sip.h:114
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.