QGIS API Documentation 3.38.0-Grenoble (exported)
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
74
76{
77 for ( const QgsRendererRange &range : mRanges )
78 {
79 if ( range.lowerValue() <= value && range.upperValue() >= value )
80 {
81 if ( range.renderState() || mCounting )
82 return &range;
83 else
84 return nullptr;
85 }
86 }
87
88 // second chance -- use a bit of double tolerance to avoid floating point equality fuzziness
89 // if a value falls just outside of a range, but within acceptable double precision tolerance
90 // then we accept it anyway
91 for ( const QgsRendererRange &range : mRanges )
92 {
93 if ( qgsDoubleNear( range.lowerValue(), value ) || qgsDoubleNear( range.upperValue(), value ) )
94 {
95 if ( range.renderState() || mCounting )
96 return &range;
97 else
98 return nullptr;
99 }
100 }
101 // the value is out of the range: return NULL instead of symbol
102 return nullptr;
103}
104
106{
107 if ( const QgsRendererRange *range = rangeForValue( value ) )
108 return range->symbol();
109 return nullptr;
110}
111
113{
114 if ( const QgsRendererRange *matchingRange = rangeForValue( value ) )
115 {
116 for ( const QgsRendererRange &range : mRanges )
117 {
118 if ( matchingRange == &range )
119 return range.uuid();
120 }
121 }
122 return QString();
123}
124
126{
127 return originalSymbolForFeature( feature, context );
128}
129
130QVariant QgsGraduatedSymbolRenderer::valueForFeature( const QgsFeature &feature, QgsRenderContext &context ) const
131{
132 QgsAttributes attrs = feature.attributes();
133 QVariant value;
134 if ( mExpression )
135 {
136 value = mExpression->evaluate( &context.expressionContext() );
137 }
138 else
139 {
140 value = attrs.value( mAttrNum );
141 }
142
143 return value;
144}
145
147{
148 QVariant value = valueForFeature( feature, context );
149
150 // Null values should not be categorized
151 if ( QgsVariantUtils::isNull( value ) )
152 return nullptr;
153
154 // find the right category
155 return symbolForValue( value.toDouble() );
156}
157
159{
160 QgsFeatureRenderer::startRender( context, fields );
161
162 mCounting = context.rendererScale() == 0.0;
163
164 // find out classification attribute index from name
165 mAttrNum = fields.lookupField( mAttrName );
166
167 if ( mAttrNum == -1 )
168 {
169 mExpression.reset( new QgsExpression( mAttrName ) );
170 mExpression->prepare( &context.expressionContext() );
171 }
172
173 for ( const QgsRendererRange &range : std::as_const( mRanges ) )
174 {
175 if ( !range.symbol() )
176 continue;
177
178 range.symbol()->startRender( context, fields );
179 }
180}
181
183{
185
186 for ( const QgsRendererRange &range : std::as_const( mRanges ) )
187 {
188 if ( !range.symbol() )
189 continue;
190
191 range.symbol()->stopRender( context );
192 }
193}
194
196{
197 QSet<QString> attributes;
198
199 // mAttrName can contain either attribute name or an expression.
200 // Sometimes it is not possible to distinguish between those two,
201 // e.g. "a - b" can be both a valid attribute name or expression.
202 // Since we do not have access to fields here, try both options.
203 attributes << mAttrName;
204
205 QgsExpression testExpr( mAttrName );
206 if ( !testExpr.hasParserError() )
207 attributes.unite( testExpr.referencedColumns() );
208
209 QgsRangeList::const_iterator range_it = mRanges.constBegin();
210 for ( ; range_it != mRanges.constEnd(); ++range_it )
211 {
212 QgsSymbol *symbol = range_it->symbol();
213 if ( symbol )
214 {
215 attributes.unite( symbol->usedAttributes( context ) );
216 }
217 }
218 return attributes;
219}
220
222{
223 QgsExpression testExpr( mAttrName );
224 if ( !testExpr.hasParserError() )
225 {
226 QgsExpressionContext context;
227 context.appendScopes( QgsExpressionContextUtils::globalProjectLayerScopes( nullptr ) ); // unfortunately no layer access available!
228 testExpr.prepare( &context );
229 return testExpr.needsGeometry();
230 }
231 return false;
232}
233
235{
236 if ( rangeIndex < 0 || rangeIndex >= mRanges.size() )
237 return false;
238 mRanges[rangeIndex].setSymbol( symbol );
239 return true;
240}
241
242bool QgsGraduatedSymbolRenderer::updateRangeLabel( int rangeIndex, const QString &label )
243{
244 if ( rangeIndex < 0 || rangeIndex >= mRanges.size() )
245 return false;
246 mRanges[rangeIndex].setLabel( label );
247 return true;
248}
249
250bool QgsGraduatedSymbolRenderer::updateRangeUpperValue( int rangeIndex, double value )
251{
252 if ( rangeIndex < 0 || rangeIndex >= mRanges.size() )
253 return false;
254 QgsRendererRange &range = mRanges[rangeIndex];
256 if ( rangeIndex == 0 )
258 else if ( rangeIndex == mRanges.count() )
260
261 bool isDefaultLabel = mClassificationMethod->labelForRange( range, pos ) == range.label();
262 range.setUpperValue( value );
263 if ( isDefaultLabel )
264 range.setLabel( mClassificationMethod->labelForRange( range, pos ) );
265
266 return true;
267}
268
269bool QgsGraduatedSymbolRenderer::updateRangeLowerValue( int rangeIndex, double value )
270{
271 if ( rangeIndex < 0 || rangeIndex >= mRanges.size() )
272 return false;
273
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.setLowerValue( value );
283 if ( isDefaultLabel )
284 range.setLabel( mClassificationMethod->labelForRange( range, pos ) );
285
286 return true;
287}
288
290{
291 if ( rangeIndex < 0 || rangeIndex >= mRanges.size() )
292 return false;
293 mRanges[rangeIndex].setRenderState( value );
294 return true;
295}
296
298{
299 QString s = QStringLiteral( "GRADUATED: attr %1\n" ).arg( mAttrName );
300 for ( int i = 0; i < mRanges.count(); i++ )
301 s += mRanges[i].dump();
302 return s;
303}
304
322
323void QgsGraduatedSymbolRenderer::toSld( QDomDocument &doc, QDomElement &element, const QVariantMap &props ) const
324{
325 QVariantMap newProps = props;
326 newProps[ QStringLiteral( "attribute" )] = mAttrName;
327 newProps[ QStringLiteral( "method" )] = graduatedMethodStr( mGraduatedMethod );
328
329 // create a Rule for each range
330 bool first = true;
331 for ( QgsRangeList::const_iterator it = mRanges.constBegin(); it != mRanges.constEnd(); ++it )
332 {
333 it->toSld( doc, element, newProps, first );
334 first = false;
335 }
336}
337
339{
340 Q_UNUSED( context )
341 QgsSymbolList lst;
342 lst.reserve( mRanges.count() );
343 for ( const QgsRendererRange &range : std::as_const( mRanges ) )
344 {
345 lst.append( range.symbol() );
346 }
347 return lst;
348}
349
351{
352 for ( const QgsRendererRange &range : std::as_const( mRanges ) )
353 {
354 QgsStyleSymbolEntity entity( range.symbol() );
355 if ( !visitor->visit( QgsStyleEntityVisitorInterface::StyleLeaf( &entity, QStringLiteral( "%1 - %2" ).arg( range.lowerValue() ).arg( range.upperValue() ), range.label() ) ) )
356 return false;
357 }
358
359 if ( mSourceColorRamp )
360 {
362 if ( !visitor->visit( QgsStyleEntityVisitorInterface::StyleLeaf( &entity ) ) )
363 return false;
364 }
365
366 return true;
367}
368
369void QgsGraduatedSymbolRenderer::makeBreaksSymmetric( QList<double> &breaks, double symmetryPoint, bool astride )
370{
372}
373
374QList<double> QgsGraduatedSymbolRenderer::calcEqualIntervalBreaks( double minimum, double maximum, int classes, bool useSymmetricMode, double symmetryPoint, bool astride )
375{
378 QList<QgsClassificationRange> _classes = method.classes( minimum, maximum, classes );
380}
381
384 QgsVectorLayer *vlayer,
385 const QString &attrName,
386 int classes,
387 Mode mode,
388 QgsSymbol *symbol,
389 QgsColorRamp *ramp,
390 const QgsRendererRangeLabelFormat &labelFormat,
391 bool useSymmetricMode,
392 double symmetryPoint,
393 const QStringList &listForCboPrettyBreaks,
394 bool astride
395)
396{
397 Q_UNUSED( listForCboPrettyBreaks )
398
401 r->setSourceSymbol( symbol->clone() );
402 r->setSourceColorRamp( ramp->clone() );
403
404 QString methodId = methodIdFromMode( mode );
406
407 if ( method )
408 {
410 method->setLabelFormat( labelFormat.format() );
413 }
414 r->setClassificationMethod( method );
415
416 QString error;
417 r->updateClasses( vlayer, classes, error );
418 ( void )error;
419
420 return r;
421}
423
425 bool useSymmetricMode, double symmetryPoint, bool astride )
426{
427 if ( mAttrName.isEmpty() )
428 return;
429
430 QString methodId = methodIdFromMode( mode );
433 setClassificationMethod( method );
434
435 QString error;
436 updateClasses( vlayer, nclasses, error );
437 ( void )error;
438}
439
440void QgsGraduatedSymbolRenderer::updateClasses( const QgsVectorLayer *vl, int nclasses, QString &error )
441{
442 Q_UNUSED( error )
444 return;
445
446 QList<QgsClassificationRange> classes = mClassificationMethod->classesV2( vl, mAttrName, nclasses, error );
447
449
450 for ( QList<QgsClassificationRange>::iterator it = classes.begin(); it != classes.end(); ++it )
451 {
453 addClass( QgsRendererRange( *it, newSymbol ) );
454 }
455 updateColorRamp( nullptr );
456}
457
464
466{
467 QDomElement symbolsElem = element.firstChildElement( QStringLiteral( "symbols" ) );
468 if ( symbolsElem.isNull() )
469 return nullptr;
470
471 QDomElement rangesElem = element.firstChildElement( QStringLiteral( "ranges" ) );
472 if ( rangesElem.isNull() )
473 return nullptr;
474
475 QgsSymbolMap symbolMap = QgsSymbolLayerUtils::loadSymbols( symbolsElem, context );
477
478 QDomElement rangeElem = rangesElem.firstChildElement();
479 int i = 0;
480 while ( !rangeElem.isNull() )
481 {
482 if ( rangeElem.tagName() == QLatin1String( "range" ) )
483 {
484 double lowerValue = rangeElem.attribute( QStringLiteral( "lower" ) ).toDouble();
485 double upperValue = rangeElem.attribute( QStringLiteral( "upper" ) ).toDouble();
486 QString symbolName = rangeElem.attribute( QStringLiteral( "symbol" ) );
487 QString label = rangeElem.attribute( QStringLiteral( "label" ) );
488 bool render = rangeElem.attribute( QStringLiteral( "render" ), QStringLiteral( "true" ) ) != QLatin1String( "false" );
489 QString uuid = rangeElem.attribute( QStringLiteral( "uuid" ), QString::number( i++ ) );
490 if ( symbolMap.contains( symbolName ) )
491 {
492 QgsSymbol *symbol = symbolMap.take( symbolName );
493 ranges.append( QgsRendererRange( lowerValue, upperValue, symbol, label, render, uuid ) );
494 }
495 }
496 rangeElem = rangeElem.nextSiblingElement();
497 }
498
499 QString attrName = element.attribute( QStringLiteral( "attr" ) );
500
502
503 QString attrMethod = element.attribute( QStringLiteral( "graduatedMethod" ) );
504 if ( !attrMethod.isEmpty() )
505 {
508 else if ( attrMethod == graduatedMethodStr( Qgis::GraduatedMethod::Size ) )
510 }
511
512
513 // delete symbols if there are any more
515
516 // try to load source symbol (optional)
517 QDomElement sourceSymbolElem = element.firstChildElement( QStringLiteral( "source-symbol" ) );
518 if ( !sourceSymbolElem.isNull() )
519 {
520 QgsSymbolMap sourceSymbolMap = QgsSymbolLayerUtils::loadSymbols( sourceSymbolElem, context );
521 if ( sourceSymbolMap.contains( QStringLiteral( "0" ) ) )
522 {
523 r->setSourceSymbol( sourceSymbolMap.take( QStringLiteral( "0" ) ) );
524 }
525 QgsSymbolLayerUtils::clearSymbolMap( sourceSymbolMap );
526 }
527
528 // try to load color ramp (optional)
529 QDomElement sourceColorRampElem = element.firstChildElement( QStringLiteral( "colorramp" ) );
530 if ( !sourceColorRampElem.isNull() && sourceColorRampElem.attribute( QStringLiteral( "name" ) ) == QLatin1String( "[source]" ) )
531 {
532 r->setSourceColorRamp( QgsSymbolLayerUtils::loadColorRamp( sourceColorRampElem ) );
533 }
534
535 // try to load mode
536
537 QDomElement modeElem = element.firstChildElement( QStringLiteral( "mode" ) ); // old format, backward compatibility
538 QDomElement methodElem = element.firstChildElement( QStringLiteral( "classificationMethod" ) );
539 QgsClassificationMethod *method = nullptr;
540
541 // TODO QGIS 4 Remove
542 // backward compatibility for QGIS project < 3.10
543 if ( !modeElem.isNull() )
544 {
545 QString modeString = modeElem.attribute( QStringLiteral( "name" ) );
546 QString methodId;
547 // the strings saved in the project does not match with the old Mode enum
548 if ( modeString == QLatin1String( "equal" ) )
549 methodId = QStringLiteral( "EqualInterval" );
550 else if ( modeString == QLatin1String( "quantile" ) )
551 methodId = QStringLiteral( "Quantile" );
552 else if ( modeString == QLatin1String( "jenks" ) )
553 methodId = QStringLiteral( "Jenks" );
554 else if ( modeString == QLatin1String( "stddev" ) )
555 methodId = QStringLiteral( "StdDev" );
556 else if ( modeString == QLatin1String( "pretty" ) )
557 methodId = QStringLiteral( "Pretty" );
558
560
561 // symmetric mode
562 QDomElement symmetricModeElem = element.firstChildElement( QStringLiteral( "symmetricMode" ) );
563 if ( !symmetricModeElem.isNull() )
564 {
565 // symmetry
566 QString symmetricEnabled = symmetricModeElem.attribute( QStringLiteral( "enabled" ) );
567 QString symmetricPointString = symmetricModeElem.attribute( QStringLiteral( "symmetryPoint" ) );
568 QString astrideEnabled = symmetricModeElem.attribute( QStringLiteral( "astride" ) );
569 method->setSymmetricMode( symmetricEnabled == QLatin1String( "true" ), symmetricPointString.toDouble(), astrideEnabled == QLatin1String( "true" ) );
570 }
571 QDomElement labelFormatElem = element.firstChildElement( QStringLiteral( "labelformat" ) );
572 if ( !labelFormatElem.isNull() )
573 {
574 // label format
575 QString format = labelFormatElem.attribute( QStringLiteral( "format" ), "%1" + QStringLiteral( " - " ) + "%2" );
576 int precision = labelFormatElem.attribute( QStringLiteral( "decimalplaces" ), QStringLiteral( "4" ) ).toInt();
577 bool trimTrailingZeroes = labelFormatElem.attribute( QStringLiteral( "trimtrailingzeroes" ), QStringLiteral( "false" ) ) == QLatin1String( "true" );
578 method->setLabelFormat( format );
579 method->setLabelPrecision( precision );
580 method->setLabelTrimTrailingZeroes( trimTrailingZeroes );
581 }
582 // End of backward compatibility
583 }
584 else
585 {
586 // QGIS project 3.10+
587 method = QgsClassificationMethod::create( methodElem, context );
588 }
589
590 // apply the method
591 r->setClassificationMethod( method );
592
593 QDomElement rotationElem = element.firstChildElement( QStringLiteral( "rotation" ) );
594 if ( !rotationElem.isNull() && !rotationElem.attribute( QStringLiteral( "field" ) ).isEmpty() )
595 {
596 for ( const QgsRendererRange &range : std::as_const( r->mRanges ) )
597 {
598 convertSymbolRotation( range.symbol(), rotationElem.attribute( QStringLiteral( "field" ) ) );
599 }
600 if ( r->mSourceSymbol )
601 {
602 convertSymbolRotation( r->mSourceSymbol.get(), rotationElem.attribute( QStringLiteral( "field" ) ) );
603 }
604 }
605 QDomElement sizeScaleElem = element.firstChildElement( QStringLiteral( "sizescale" ) );
606 if ( !sizeScaleElem.isNull() && !sizeScaleElem.attribute( QStringLiteral( "field" ) ).isEmpty() )
607 {
608 for ( const QgsRendererRange &range : std::as_const( r->mRanges ) )
609 {
610 convertSymbolSizeScale( range.symbol(),
611 QgsSymbolLayerUtils::decodeScaleMethod( sizeScaleElem.attribute( QStringLiteral( "scalemethod" ) ) ),
612 sizeScaleElem.attribute( QStringLiteral( "field" ) ) );
613 }
614 if ( r->mSourceSymbol && r->mSourceSymbol->type() == Qgis::SymbolType::Marker )
615 {
617 QgsSymbolLayerUtils::decodeScaleMethod( sizeScaleElem.attribute( QStringLiteral( "scalemethod" ) ) ),
618 sizeScaleElem.attribute( QStringLiteral( "field" ) ) );
619 }
620 }
621
622 QDomElement ddsLegendSizeElem = element.firstChildElement( QStringLiteral( "data-defined-size-legend" ) );
623 if ( !ddsLegendSizeElem.isNull() )
624 {
625 r->mDataDefinedSizeLegend.reset( QgsDataDefinedSizeLegend::readXml( ddsLegendSizeElem, context ) );
626 }
627// TODO: symbol levels
628 return r;
629}
630
631QDomElement QgsGraduatedSymbolRenderer::save( QDomDocument &doc, const QgsReadWriteContext &context )
632{
633 QDomElement rendererElem = doc.createElement( RENDERER_TAG_NAME );
634 rendererElem.setAttribute( QStringLiteral( "type" ), QStringLiteral( "graduatedSymbol" ) );
635 rendererElem.setAttribute( QStringLiteral( "attr" ), mAttrName );
636 rendererElem.setAttribute( QStringLiteral( "graduatedMethod" ), graduatedMethodStr( mGraduatedMethod ) );
637
638 // ranges
639 int i = 0;
641 QDomElement rangesElem = doc.createElement( QStringLiteral( "ranges" ) );
642 QgsRangeList::const_iterator it = mRanges.constBegin();
643 for ( ; it != mRanges.constEnd(); ++it )
644 {
645 const QgsRendererRange &range = *it;
646 QString symbolName = QString::number( i );
647 symbols.insert( symbolName, range.symbol() );
648
649 QDomElement rangeElem = doc.createElement( QStringLiteral( "range" ) );
650 rangeElem.setAttribute( QStringLiteral( "lower" ), QString::number( range.lowerValue(), 'f', 15 ) );
651 rangeElem.setAttribute( QStringLiteral( "upper" ), QString::number( range.upperValue(), 'f', 15 ) );
652 rangeElem.setAttribute( QStringLiteral( "symbol" ), symbolName );
653 rangeElem.setAttribute( QStringLiteral( "label" ), range.label() );
654 rangeElem.setAttribute( QStringLiteral( "render" ), range.renderState() ? QStringLiteral( "true" ) : QStringLiteral( "false" ) );
655 rangeElem.setAttribute( QStringLiteral( "uuid" ), range.uuid() );
656 rangesElem.appendChild( rangeElem );
657 i++;
658 }
659
660 rendererElem.appendChild( rangesElem );
661
662 // save symbols
663 QDomElement symbolsElem = QgsSymbolLayerUtils::saveSymbols( symbols, QStringLiteral( "symbols" ), doc, context );
664 rendererElem.appendChild( symbolsElem );
665
666 // save source symbol
667 if ( mSourceSymbol )
668 {
669 QgsSymbolMap sourceSymbols;
670 sourceSymbols.insert( QStringLiteral( "0" ), mSourceSymbol.get() );
671 QDomElement sourceSymbolElem = QgsSymbolLayerUtils::saveSymbols( sourceSymbols, QStringLiteral( "source-symbol" ), doc, context );
672 rendererElem.appendChild( sourceSymbolElem );
673 }
674
675 // save source color ramp
676 if ( mSourceColorRamp )
677 {
678 QDomElement colorRampElem = QgsSymbolLayerUtils::saveColorRamp( QStringLiteral( "[source]" ), mSourceColorRamp.get(), doc );
679 rendererElem.appendChild( colorRampElem );
680 }
681
682 // save classification method
683 QDomElement classificationMethodElem = mClassificationMethod->save( doc, context );
684 rendererElem.appendChild( classificationMethodElem );
685
686 QDomElement rotationElem = doc.createElement( QStringLiteral( "rotation" ) );
687 rendererElem.appendChild( rotationElem );
688
689 QDomElement sizeScaleElem = doc.createElement( QStringLiteral( "sizescale" ) );
690 rendererElem.appendChild( sizeScaleElem );
691
693 {
694 QDomElement ddsLegendElem = doc.createElement( QStringLiteral( "data-defined-size-legend" ) );
695 mDataDefinedSizeLegend->writeXml( ddsLegendElem, context );
696 rendererElem.appendChild( ddsLegendElem );
697 }
698
699 saveRendererData( doc, rendererElem, context );
700
701 return rendererElem;
702}
703
704QgsLegendSymbolList QgsGraduatedSymbolRenderer::baseLegendSymbolItems() const
705{
707 lst.reserve( mRanges.size() );
708 for ( const QgsRendererRange &range : mRanges )
709 {
710 lst << QgsLegendSymbolItem( range.symbol(), range.label(), range.uuid(), true );
711 }
712 return lst;
713}
714
716QString QgsGraduatedSymbolRenderer::methodIdFromMode( QgsGraduatedSymbolRenderer::Mode mode )
717{
718 switch ( mode )
719 {
720 case EqualInterval:
721 return QStringLiteral( "EqualInterval" );
722 case Quantile:
723 return QStringLiteral( "Quantile" );
724 case Jenks:
725 return QStringLiteral( "Jenks" );
726 case StdDev:
727 return QStringLiteral( "StdDev" );
728 case Pretty:
729 return QStringLiteral( "Pretty" );
730 case Custom:
731 return QString();
732 }
733 return QString();
734}
735
736QgsGraduatedSymbolRenderer::Mode QgsGraduatedSymbolRenderer::modeFromMethodId( const QString &methodId )
737{
738 if ( methodId == QLatin1String( "EqualInterval" ) )
739 return EqualInterval;
740 if ( methodId == QLatin1String( "Quantile" ) )
741 return Quantile;
742 if ( methodId == QLatin1String( "Jenks" ) )
743 return Jenks;
744 if ( methodId == QLatin1String( "StdDev" ) )
745 return StdDev;
746 if ( methodId == QLatin1String( "Pretty" ) )
747 return Pretty;
748 else
749 return Custom;
750}
752
754{
756 {
757 // check that all symbols that have the same size expression
758 QgsProperty ddSize;
759 for ( const QgsRendererRange &range : mRanges )
760 {
761 const QgsMarkerSymbol *symbol = static_cast<const QgsMarkerSymbol *>( range.symbol() );
762 if ( ddSize )
763 {
764 QgsProperty sSize( symbol->dataDefinedSize() );
765 if ( sSize && sSize != ddSize )
766 {
767 // no common size expression
768 return baseLegendSymbolItems();
769 }
770 }
771 else
772 {
773 ddSize = symbol->dataDefinedSize();
774 }
775 }
776
777 if ( ddSize && ddSize.isActive() )
778 {
780
782 ddSizeLegend.updateFromSymbolAndProperty( static_cast<const QgsMarkerSymbol *>( mSourceSymbol.get() ), ddSize );
783 lst += ddSizeLegend.legendSymbolList();
784
785 lst += baseLegendSymbolItems();
786 return lst;
787 }
788 }
789
790 return baseLegendSymbolItems();
791}
792
793QSet< QString > QgsGraduatedSymbolRenderer::legendKeysForFeature( const QgsFeature &feature, QgsRenderContext &context ) const
794{
795 QVariant value = valueForFeature( feature, context );
796
797 // Null values should not be categorized
798 if ( QgsVariantUtils::isNull( value ) )
799 return QSet< QString >();
800
801 // find the right category
802 QString key = legendKeyForValue( value.toDouble() );
803 if ( !key.isNull() )
804 return QSet< QString >() << key;
805 else
806 return QSet< QString >();
807}
808
809QString QgsGraduatedSymbolRenderer::legendKeyToExpression( const QString &key, QgsVectorLayer *layer, bool &ok ) const
810{
811 ok = false;
812 int i = 0;
813 for ( i = 0; i < mRanges.size(); i++ )
814 {
815 if ( mRanges[i].uuid() == key )
816 {
817 ok = true;
818 break;
819 }
820 }
821
822 if ( !ok )
823 {
824 ok = false;
825 return QString();
826 }
827
828 const QString attributeComponent = QgsExpression::quoteFieldExpression( mAttrName, layer );
829 const QgsRendererRange &range = mRanges[i];
830
831 return QStringLiteral( "(%1 >= %2) AND (%1 <= %3)" ).arg( attributeComponent, QgsExpression::quotedValue( range.lowerValue(), QMetaType::Type::Double ),
832 QgsExpression::quotedValue( range.upperValue(), QMetaType::Type::Double ) );
833}
834
839
841{
842 return mSourceSymbol.get();
843}
844
849
854
859
861{
862 if ( ramp == mSourceColorRamp.get() )
863 return;
864
865 mSourceColorRamp.reset( ramp );
866}
867
869{
870 double min = std::numeric_limits<double>::max();
871 for ( int i = 0; i < mRanges.count(); i++ )
872 {
873 double sz = 0;
874 if ( mRanges[i].symbol()->type() == Qgis::SymbolType::Marker )
875 sz = static_cast< QgsMarkerSymbol * >( mRanges[i].symbol() )->size();
876 else if ( mRanges[i].symbol()->type() == Qgis::SymbolType::Line )
877 sz = static_cast< QgsLineSymbol * >( mRanges[i].symbol() )->width();
878 min = std::min( sz, min );
879 }
880 return min;
881}
882
884{
885 double max = std::numeric_limits<double>::min();
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 max = std::max( sz, max );
894 }
895 return max;
896}
897
898void QgsGraduatedSymbolRenderer::setSymbolSizes( double minSize, double maxSize )
899{
900 for ( int i = 0; i < mRanges.count(); i++ )
901 {
902 std::unique_ptr<QgsSymbol> symbol( mRanges.at( i ).symbol() ? mRanges.at( i ).symbol()->clone() : nullptr );
903 const double size = mRanges.count() > 1
904 ? minSize + i * ( maxSize - minSize ) / ( mRanges.count() - 1 )
905 : .5 * ( maxSize + minSize );
906 if ( symbol->type() == Qgis::SymbolType::Marker )
907 static_cast< QgsMarkerSymbol * >( symbol.get() )->setSize( size );
908 if ( symbol->type() == Qgis::SymbolType::Line )
909 static_cast< QgsLineSymbol * >( symbol.get() )->setWidth( size );
910 updateRangeSymbol( i, symbol.release() );
911 }
912}
913
915{
916 int i = 0;
917 if ( ramp )
918 {
919 setSourceColorRamp( ramp );
920 }
921
922 if ( mSourceColorRamp )
923 {
924 for ( const QgsRendererRange &range : std::as_const( mRanges ) )
925 {
926 QgsSymbol *symbol = range.symbol() ? range.symbol()->clone() : nullptr;
927 if ( symbol )
928 {
929 double colorValue;
930 colorValue = ( mRanges.count() > 1 ? static_cast< double >( i ) / ( mRanges.count() - 1 ) : 0 );
931 symbol->setColor( mSourceColorRamp->color( colorValue ) );
932 }
933 updateRangeSymbol( i, symbol );
934 ++i;
935 }
936 }
937
938}
939
941{
942 if ( !sym )
943 return;
944
945 int i = 0;
946 for ( const QgsRendererRange &range : std::as_const( mRanges ) )
947 {
948 std::unique_ptr<QgsSymbol> symbol( sym->clone() );
949 switch ( mGraduatedMethod )
950 {
952 {
953 symbol->setColor( range.symbol()->color() );
954 break;
955 }
957 {
958 if ( symbol->type() == Qgis::SymbolType::Marker )
959 static_cast<QgsMarkerSymbol *>( symbol.get() )->setSize(
960 static_cast<QgsMarkerSymbol *>( range.symbol() )->size() );
961 else if ( symbol->type() == Qgis::SymbolType::Line )
962 static_cast<QgsLineSymbol *>( symbol.get() )->setWidth(
963 static_cast<QgsLineSymbol *>( range.symbol() )->width() );
964 break;
965 }
966 }
967 updateRangeSymbol( i, symbol.release() );
968 ++i;
969 }
970 setSourceSymbol( sym->clone() );
971}
972
974{
975 return true;
976}
977
979{
980 for ( const QgsRendererRange &range : std::as_const( mRanges ) )
981 {
982 if ( range.uuid() == key )
983 {
984 return range.renderState();
985 }
986 }
987 return true;
988}
989
990void QgsGraduatedSymbolRenderer::checkLegendSymbolItem( const QString &key, bool state )
991{
992 for ( int i = 0; i < mRanges.size(); i++ )
993 {
994 if ( mRanges[i].uuid() == key )
995 {
996 updateRangeRenderState( i, state );
997 break;
998 }
999 }
1000}
1001
1003{
1004 bool ok = false;
1005 int i = 0;
1006 for ( i = 0; i < mRanges.size(); i++ )
1007 {
1008 if ( mRanges[i].uuid() == key )
1009 {
1010 ok = true;
1011 break;
1012 }
1013 }
1014
1015 if ( ok )
1016 updateRangeSymbol( i, symbol );
1017 else
1018 delete symbol;
1019}
1020
1022{
1023 QgsSymbol *newSymbol = symbol->clone();
1024 QString label = QStringLiteral( "0.0 - 0.0" );
1025 mRanges.insert( 0, QgsRendererRange( 0.0, 0.0, newSymbol, label ) );
1026}
1027
1028void QgsGraduatedSymbolRenderer::addClass( double lower, double upper )
1029{
1030 QgsSymbol *newSymbol = mSourceSymbol->clone();
1031 QString label = mClassificationMethod->labelForRange( lower, upper );
1032 mRanges.append( QgsRendererRange( lower, upper, newSymbol, label ) );
1033}
1034
1035void QgsGraduatedSymbolRenderer::addBreak( double breakValue, bool updateSymbols )
1036{
1037 QMutableListIterator< QgsRendererRange > it( mRanges );
1038 while ( it.hasNext() )
1039 {
1040 QgsRendererRange range = it.next();
1041 if ( range.lowerValue() < breakValue && range.upperValue() > breakValue )
1042 {
1044 newRange.setLowerValue( breakValue );
1045 newRange.setUpperValue( range.upperValue() );
1046 newRange.setLabel( mClassificationMethod->labelForRange( newRange ) );
1047 newRange.setSymbol( mSourceSymbol->clone() );
1048
1049 //update old range
1050 bool isDefaultLabel = range.label() == mClassificationMethod->labelForRange( range );
1051 range.setUpperValue( breakValue );
1052 if ( isDefaultLabel )
1053 range.setLabel( mClassificationMethod->labelForRange( range.lowerValue(), breakValue ) );
1054 it.setValue( range );
1055
1056 it.insert( newRange );
1057 break;
1058 }
1059 }
1060
1061 if ( updateSymbols )
1062 {
1063 switch ( mGraduatedMethod )
1064 {
1067 break;
1070 break;
1071 }
1072 }
1073}
1074
1076{
1077 mRanges.append( range );
1078}
1079
1081{
1082 mRanges.removeAt( idx );
1083}
1084
1089
1092{
1093 mClassificationMethod->setLabelFormat( labelFormat.format() );
1094 mClassificationMethod->setLabelPrecision( labelFormat.precision() );
1095 mClassificationMethod->setLabelTrimTrailingZeroes( labelFormat.trimTrailingZeroes() );
1096
1097 if ( updateRanges )
1098 {
1100 }
1101}
1103
1105{
1106 for ( int i = 0; i < mRanges.count(); i++ )
1107 {
1109 if ( i == 0 )
1111 else if ( i == mRanges.count() - 1 )
1113 mRanges[i].setLabel( mClassificationMethod->labelForRange( mRanges[i], pos ) );
1114 }
1115}
1116
1118{
1119 // Find the minimum size of a class
1120 double minClassRange = 0.0;
1121 for ( const QgsRendererRange &rendererRange : std::as_const( mRanges ) )
1122 {
1123 double range = rendererRange.upperValue() - rendererRange.lowerValue();
1124 if ( range <= 0.0 )
1125 continue;
1126 if ( minClassRange == 0.0 || range < minClassRange )
1127 minClassRange = range;
1128 }
1129 if ( minClassRange <= 0.0 )
1130 return;
1131
1132 // Now set the number of decimal places to ensure no more than 20% error in
1133 // representing this range (up to 10% at upper and lower end)
1134
1135 int ndp = 10;
1136 double nextDpMinRange = 0.0000000099;
1137 while ( ndp > 0 && nextDpMinRange < minClassRange )
1138 {
1139 ndp--;
1140 nextDpMinRange *= 10.0;
1141 }
1142 mClassificationMethod->setLabelPrecision( ndp );
1143 if ( updateRanges )
1145}
1146
1148{
1149 if ( from < 0 || from >= mRanges.size() || to < 0 || to >= mRanges.size() )
1150 return;
1151 mRanges.move( from, to );
1152}
1153
1155{
1156 return r1 < r2;
1157}
1158
1160{
1161 return !valueLessThan( r1, r2 );
1162}
1163
1165{
1166 if ( order == Qt::AscendingOrder )
1167 {
1168 std::sort( mRanges.begin(), mRanges.end(), valueLessThan );
1169 }
1170 else
1171 {
1172 std::sort( mRanges.begin(), mRanges.end(), valueGreaterThan );
1173 }
1174}
1175
1177{
1178 QgsRangeList sortedRanges = mRanges;
1179 std::sort( sortedRanges.begin(), sortedRanges.end(), valueLessThan );
1180
1181 QgsRangeList::const_iterator it = sortedRanges.constBegin();
1182 if ( it == sortedRanges.constEnd() )
1183 return false;
1184
1185 if ( ( *it ).upperValue() < ( *it ).lowerValue() )
1186 return true;
1187
1188 double prevMax = ( *it ).upperValue();
1189 ++it;
1190
1191 for ( ; it != sortedRanges.constEnd(); ++it )
1192 {
1193 if ( ( *it ).upperValue() < ( *it ).lowerValue() )
1194 return true;
1195
1196 if ( ( *it ).lowerValue() < prevMax )
1197 return true;
1198
1199 prevMax = ( *it ).upperValue();
1200 }
1201 return false;
1202}
1203
1205{
1206 QgsRangeList sortedRanges = mRanges;
1207 std::sort( sortedRanges.begin(), sortedRanges.end(), valueLessThan );
1208
1209 QgsRangeList::const_iterator it = sortedRanges.constBegin();
1210 if ( it == sortedRanges.constEnd() )
1211 return false;
1212
1213 double prevMax = ( *it ).upperValue();
1214 ++it;
1215
1216 for ( ; it != sortedRanges.constEnd(); ++it )
1217 {
1218 if ( !qgsDoubleNear( ( *it ).lowerValue(), prevMax ) )
1219 return true;
1220
1221 prevMax = ( *it ).upperValue();
1222 }
1223 return false;
1224}
1225
1227{
1228 return QString::localeAwareCompare( r1.label(), r2.label() ) < 0;
1229}
1230
1232{
1233 return !labelLessThan( r1, r2 );
1234}
1235
1237{
1238 if ( order == Qt::AscendingOrder )
1239 {
1240 std::sort( mRanges.begin(), mRanges.end(), labelLessThan );
1241 }
1242 else
1243 {
1244 std::sort( mRanges.begin(), mRanges.end(), labelGreaterThan );
1245 }
1246}
1247
1252
1257
1259{
1260 QString methodId = methodIdFromMode( mode );
1262 setClassificationMethod( method );
1263}
1264
1266{
1267 mClassificationMethod->setSymmetricMode( useSymmetricMode, mClassificationMethod->symmetryPoint(), mClassificationMethod->symmetryAstride() );
1268}
1269
1271{
1272 mClassificationMethod->setSymmetricMode( mClassificationMethod->symmetricModeEnabled(), symmetryPoint, mClassificationMethod->symmetryAstride() );
1273}
1274
1276{
1277 mClassificationMethod->setSymmetricMode( mClassificationMethod->symmetricModeEnabled(), mClassificationMethod->symmetryPoint(), astride );
1278}
1279
1281{
1282 std::unique_ptr< QgsGraduatedSymbolRenderer > r;
1283 if ( renderer->type() == QLatin1String( "graduatedSymbol" ) )
1284 {
1285 r.reset( static_cast<QgsGraduatedSymbolRenderer *>( renderer->clone() ) );
1286 }
1287 else if ( renderer->type() == QLatin1String( "categorizedSymbol" ) )
1288 {
1289 const QgsCategorizedSymbolRenderer *categorizedSymbolRenderer = dynamic_cast<const QgsCategorizedSymbolRenderer *>( renderer );
1290 if ( categorizedSymbolRenderer )
1291 {
1292 r = std::make_unique< QgsGraduatedSymbolRenderer >( QString(), QgsRangeList() );
1293 if ( categorizedSymbolRenderer->sourceSymbol() )
1294 r->setSourceSymbol( categorizedSymbolRenderer->sourceSymbol()->clone() );
1295 if ( categorizedSymbolRenderer->sourceColorRamp() )
1296 {
1297 bool isRandom = dynamic_cast<const QgsRandomColorRamp *>( categorizedSymbolRenderer->sourceColorRamp() ) ||
1298 dynamic_cast<const QgsLimitedRandomColorRamp *>( categorizedSymbolRenderer->sourceColorRamp() );
1299 if ( !isRandom )
1300 r->setSourceColorRamp( categorizedSymbolRenderer->sourceColorRamp()->clone() );
1301 }
1302 r->setClassAttribute( categorizedSymbolRenderer->classAttribute() );
1303 }
1304 }
1305 else if ( renderer->type() == QLatin1String( "pointDisplacement" ) || renderer->type() == QLatin1String( "pointCluster" ) )
1306 {
1307 const QgsPointDistanceRenderer *pointDistanceRenderer = dynamic_cast<const QgsPointDistanceRenderer *>( renderer );
1308 if ( pointDistanceRenderer )
1309 r.reset( convertFromRenderer( pointDistanceRenderer->embeddedRenderer() ) );
1310 }
1311 else if ( renderer->type() == QLatin1String( "invertedPolygonRenderer" ) )
1312 {
1313 const QgsInvertedPolygonRenderer *invertedPolygonRenderer = dynamic_cast<const QgsInvertedPolygonRenderer *>( renderer );
1314 if ( invertedPolygonRenderer )
1315 r.reset( convertFromRenderer( invertedPolygonRenderer->embeddedRenderer() ) );
1316 }
1317
1318 // If not one of the specifically handled renderers, then just grab the symbol from the renderer
1319 // Could have applied this to specific renderer types (singleSymbol, graduatedSymbol)
1320
1321 if ( !r )
1322 {
1323 r = std::make_unique< QgsGraduatedSymbolRenderer >( QString(), QgsRangeList() );
1324 QgsRenderContext context;
1325 QgsSymbolList symbols = const_cast<QgsFeatureRenderer *>( renderer )->symbols( context );
1326 if ( !symbols.isEmpty() )
1327 {
1328 r->setSourceSymbol( symbols.at( 0 )->clone() );
1329 }
1330 }
1331
1332 renderer->copyRendererData( r.get() );
1333
1334 return r.release();
1335}
1336
1341
1346
1348{
1349 switch ( method )
1350 {
1352 return QStringLiteral( "GraduatedColor" );
1354 return QStringLiteral( "GraduatedSize" );
1355 }
1356 return QString();
1357}
1358
1359
GraduatedMethod
Methods for modifying symbols by range in a graduated symbol renderer.
Definition qgis.h:2827
@ Size
Alter size of symbols.
@ Color
Alter color of symbols.
@ Marker
Marker symbol.
@ Line
Line symbol.
static QgsClassificationMethodRegistry * classificationMethodRegistry()
Returns the application's classification methods registry, used in graduated renderer.
A vector of attributes.
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.
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...
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 setLabelTrimTrailingZeroes(bool trimTrailingZeroes)
Defines if the trailing 0 are trimmed in the label.
void setSymmetricMode(bool enabled, double symmetryPoint=0, bool symmetryAstride=false)
Defines if the symmetric mode is enables and configures its parameters.
ClassPosition
Defines the class position.
@ LowerBound
The class is at the lower bound.
@ UpperBound
The class is at the upper bound.
@ Inner
The class is not at a bound.
static QList< double > rangesToBreaks(const QList< QgsClassificationRange > &classes)
Transforms a list of classes to a list of breaks.
void setLabelFormat(const QString &format)
Defines the format of the labels for the classes, using %1 and %2 for the bounds.
static QgsClassificationMethod * create(const QDomElement &element, const QgsReadWriteContext &context)
Reads the DOM element and return a new classification method from it.
void setLabelPrecision(int labelPrecision)
Defines the precision for the formatting of the labels.
Abstract base class for color ramps.
virtual QgsColorRamp * clone() const =0
Creates a clone of the color ramp.
Object that keeps configuration of appearance of marker symbol's data-defined size in legend.
static QgsDataDefinedSizeLegend * readXml(const QDomElement &elem, const QgsReadWriteContext &context) SIP_FACTORY
Creates instance from given element and returns it (caller takes ownership). Returns nullptr on error...
void updateFromSymbolAndProperty(const QgsMarkerSymbol *symbol, const QgsProperty &ddSize)
Updates the list of classes, source symbol and title label from given symbol and property.
QgsLegendSymbolList legendSymbolList() const
Generates legend symbol items according to the configuration.
static QList< QgsExpressionContextScope * > globalProjectLayerScopes(const QgsMapLayer *layer)
Creates a list of three scopes: global, layer's project and layer.
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
void appendScopes(const QList< QgsExpressionContextScope * > &scopes)
Appends a list of scopes to the end of the context.
Class for parsing and evaluation of expressions (formerly called "search strings").
bool prepare(const QgsExpressionContext *context)
Gets the expression ready for evaluation - find out column indexes.
static QString quotedValue(const QVariant &value)
Returns a string representation of a literal value, including appropriate quotations where required.
static QString quoteFieldExpression(const QString &expression, const QgsVectorLayer *layer)
Validate if the expression is a field in the layer and ensure it is quoted.
bool hasParserError() const
Returns true if an error occurred when parsing the input expression.
QSet< QString > referencedColumns() const
Gets list of columns referenced by the expression.
bool needsGeometry() const
Returns true if the expression uses feature geometry for some computation.
virtual void stopRender(QgsRenderContext &context)
Must be called when a render cycle has finished, to allow the renderer to clean up.
QString type() const
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.
QgsLegendSymbolList legendSymbolItems() const override
Returns a list of symbology items for the legend.
QgsSymbol * sourceSymbol()
Returns the renderer's source symbol, which is the base symbol used for the each classes' symbol befo...
QDomElement save(QDomDocument &doc, const QgsReadWriteContext &context) override
Stores renderer properties to an XML element.
void updateSymbols(QgsSymbol *sym)
Update all the symbols but leave breaks and colors.
const QgsRendererRange * rangeForValue(double value) const
Returns the renderer range matching the provided value, or nullptr if no range matches the value.
QgsColorRamp * sourceColorRamp()
Returns the source color ramp, from which each classes' color is derived.
bool updateRangeSymbol(int rangeIndex, QgsSymbol *symbol)
void addBreak(double breakValue, bool updateSymbols=true)
Add a breakpoint by splitting existing classes so that the specified value becomes a break between tw...
Q_DECL_DEPRECATED void setAstride(bool astride)
Set if we want a central class astride the pivot value.
void setClassificationMethod(QgsClassificationMethod *method)
Defines the classification method This will take ownership of the method.
static Q_DECL_DEPRECATED QList< double > calcEqualIntervalBreaks(double minimum, double maximum, int classes, bool useSymmetricMode, double symmetryPoint, bool astride)
Compute the equal interval classification.
QgsGraduatedSymbolRenderer * clone() const override
Create a deep copy of this renderer.
std::unique_ptr< QgsDataDefinedSizeLegend > mDataDefinedSizeLegend
static Q_DECL_DEPRECATED void makeBreaksSymmetric(QList< double > &breaks, double symmetryPoint, bool astride)
Remove the breaks that are above the existing opposite sign classes to keep colors symmetrically bala...
void startRender(QgsRenderContext &context, const QgsFields &fields) override
Must be called when a new render cycle is started.
double maxSymbolSize() const
Returns the max symbol size when graduated by size.
Q_DECL_DEPRECATED bool useSymmetricMode() const
Returns if we want to classify symmetric around a given value.
bool updateRangeLabel(int rangeIndex, const QString &label)
QgsClassificationMethod * classificationMethod() const
Returns the classification method.
QgsSymbol * originalSymbolForFeature(const QgsFeature &feature, QgsRenderContext &context) const override
Returns symbol for feature.
void sortByValue(Qt::SortOrder order=Qt::AscendingOrder)
void toSld(QDomDocument &doc, QDomElement &element, const QVariantMap &props=QVariantMap()) const override
used from subclasses to create SLD Rule elements following SLD v1.1 specs
void checkLegendSymbolItem(const QString &key, bool state=true) override
Sets whether the legend symbology item with the specified ley should be checked.
std::unique_ptr< QgsSymbol > mSourceSymbol
void setLegendSymbolItem(const QString &key, QgsSymbol *symbol) override
Sets the symbol to be used for a legend symbol item.
void setGraduatedMethod(Qgis::GraduatedMethod method)
Set the method used for graduation (either size or color).
static QgsFeatureRenderer * create(QDomElement &element, const QgsReadWriteContext &context)
create renderer from XML element
Q_DECL_DEPRECATED void setMode(Mode mode)
QSet< QString > legendKeysForFeature(const QgsFeature &feature, QgsRenderContext &context) const override
Returns legend keys matching a specified feature.
bool rangesOverlap() const
Tests whether classes assigned to the renderer have ranges which overlap.
std::shared_ptr< QgsClassificationMethod > mClassificationMethod
Q_DECL_DEPRECATED bool astride() const
Returns if we want to have a central class astride the pivot value.
Q_DECL_DEPRECATED void setLabelFormat(const QgsRendererRangeLabelFormat &labelFormat, bool updateRanges=false)
Set the label format used to generate default classification labels.
Q_DECL_DEPRECATED void updateClasses(QgsVectorLayer *vlayer, Mode mode, int nclasses, bool useSymmetricMode=false, double symmetryPoint=0.0, bool astride=false)
Recalculate classes for a layer.
QString dump() const override
Returns debug information about this renderer.
bool updateRangeUpperValue(int rangeIndex, double value)
QString legendKeyToExpression(const QString &key, QgsVectorLayer *layer, bool &ok) const override
Attempts to convert the specified legend rule key to a QGIS expression matching the features displaye...
QString legendKeyForValue(double value) const
Returns the matching legend key for a value.
void setSourceColorRamp(QgsColorRamp *ramp)
Sets the source color ramp.
void setSourceSymbol(QgsSymbol *sym)
Sets the source symbol for the renderer, which is the base symbol used for the each classes' symbol b...
bool legendSymbolItemChecked(const QString &key) override
Returns true if the legend symbology item with the specified key is checked.
bool updateRangeLowerValue(int rangeIndex, double value)
void stopRender(QgsRenderContext &context) override
Must be called when a render cycle has finished, to allow the renderer to clean up.
static QgsGraduatedSymbolRenderer * convertFromRenderer(const QgsFeatureRenderer *renderer)
creates a QgsGraduatedSymbolRenderer from an existing renderer.
bool legendSymbolItemsCheckable() const override
Returns true if symbology items in legend are checkable.
void moveClass(int from, int to)
Moves the category at index position from to index position to.
void sortByLabel(Qt::SortOrder order=Qt::AscendingOrder)
QSet< QString > usedAttributes(const QgsRenderContext &context) const override
Returns a list of attributes required by this renderer.
void updateRangeLabels()
Updates the labels of the ranges.
bool updateRangeRenderState(int rangeIndex, bool render)
QgsSymbol * symbolForFeature(const QgsFeature &feature, QgsRenderContext &context) const override
To be overridden.
std::unique_ptr< QgsColorRamp > mSourceColorRamp
QgsSymbolList symbols(QgsRenderContext &context) const override
Returns list of symbols used by the renderer.
bool accept(QgsStyleEntityVisitorInterface *visitor) const override
Accepts the specified symbology visitor, causing it to visit all symbols associated with the renderer...
QgsDataDefinedSizeLegend * dataDefinedSizeLegend() const
Returns configuration of appearance of legend when using data-defined size for marker symbols.
void updateColorRamp(QgsColorRamp *ramp=nullptr)
Update the color ramp used.
Q_DECL_DEPRECATED Mode mode() const
QgsGraduatedSymbolRenderer(const QString &attrName=QString(), const QgsRangeList &ranges=QgsRangeList())
double minSymbolSize() const
Returns the min symbol size when graduated by size.
Qgis::GraduatedMethod graduatedMethod() const
Returns the method used for graduation (either size or color).
bool filterNeedsGeometry() const override
Returns true if this renderer requires the geometry to apply the filter.
int mAttrNum
attribute index (derived from attribute name in startRender)
Q_DECL_DEPRECATED void setSymmetryPoint(double symmetryPoint)
Set the pivot point.
std::unique_ptr< QgsExpression > mExpression
static QString graduatedMethodStr(Qgis::GraduatedMethod method)
void setSymbolSizes(double minSize, double maxSize)
set varying symbol size for classes
void calculateLabelPrecision(bool updateRanges=true)
Reset the label decimal places to a numberbased on the minimum class interval.
void setDataDefinedSizeLegend(QgsDataDefinedSizeLegend *settings)
Configures appearance of legend when renderer is configured to use data-defined size for marker symbo...
const QgsRangeList & ranges() const
Returns a list of all ranges used in the classification.
Q_DECL_DEPRECATED QgsRendererRangeLabelFormat labelFormat() const
Returns the label format used to generate default classification labels.
static Q_DECL_DEPRECATED QgsGraduatedSymbolRenderer * createRenderer(QgsVectorLayer *vlayer, const QString &attrName, int classes, Mode mode, QgsSymbol *symbol, QgsColorRamp *ramp, const QgsRendererRangeLabelFormat &legendFormat=QgsRendererRangeLabelFormat(), bool useSymmetricMode=false, double symmetryPoint=0.0, const QStringList &listForCboPrettyBreaks=QStringList(), bool astride=false)
Creates a new graduated renderer.
Q_DECL_DEPRECATED double symmetryPoint() const
Returns the pivot value for symmetric classification.
Q_DECL_DEPRECATED void setUseSymmetricMode(bool useSymmetricMode)
Set if we want to classify symmetric around a given value.
QgsSymbol * symbolForValue(double value) const
Gets the symbol which is used to represent value.
bool rangesHaveGaps() const
Tests whether classes assigned to the renderer have gaps between the ranges.
QgsInvertedPolygonRenderer is a polygon-only feature renderer used to display features inverted,...
The class stores information about one class/rule of a vector layer renderer in a unified way that ca...
Constrained random color ramp, which returns random colors based on preset parameters.
A line symbol type, for rendering LineString and MultiLineString geometries.
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:1404
An interface for classes which can visit style entity (e.g.
virtual bool visit(const QgsStyleEntityVisitorInterface::StyleLeaf &entity)
Called when the visitor will visit a style entity.
A symbol entity for QgsStyle databases.
Definition qgsstyle.h:1372
static QgsColorRamp * loadColorRamp(QDomElement &element)
Creates a color ramp from the settings encoded in an XML element.
static Qgis::ScaleMethod decodeScaleMethod(const QString &str)
Decodes a symbol scale method from a string.
static QDomElement saveColorRamp(const QString &name, QgsColorRamp *ramp, QDomDocument &doc)
Encodes a color ramp's settings to an XML element.
static void clearSymbolMap(QgsSymbolMap &symbols)
static QgsSymbolMap loadSymbols(QDomElement &element, const QgsReadWriteContext &context)
Reads a collection of symbols from XML and returns them in a map. Caller is responsible for deleting ...
static QDomElement saveSymbols(QgsSymbolMap &symbols, const QString &tagName, QDomDocument &doc, const QgsReadWriteContext &context)
Writes a collection of symbols to XML with specified tagName for the top-level element.
Abstract base class for all rendered symbols.
Definition qgssymbol.h:94
void setColor(const QColor &color) const
Sets the color for the symbol.
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:6022
#define Q_NOWARN_DEPRECATED_PUSH
Definition qgis.h:6021
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)
Definition qgis.h:5445
#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.