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