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