32using namespace Qt::StringLiterals;
43 if ( mFillSymbols.empty() )
48 const QList<QgsAbstractPlotSeries *> seriesList = plotData.
series();
49 if ( seriesList.isEmpty() || plotData.
categories().isEmpty() )
54 const QStringList categories = plotData.
categories();
55 double maxLabelHeight = 0;
60 for (
const QString &category : categories )
76 const QList<std::pair<double, double>> data = xySeries->data();
77 for (
const std::pair<double, double> &pair : data )
81 text = mNumericFormat->formatDouble( pair.second, numericContext );
85 text = QString::number( pair.second );
102 context.
painter()->setClipRect( plotArea );
104 const bool pieStackHorizontal = plotArea.width() >= plotArea.height();
105 const double pieStackCount = seriesList.size();
107 if ( pieStackHorizontal )
109 pieArea = plotArea.height() * pieStackCount > plotArea.width() ? plotArea.width() / pieStackCount : plotArea.height();
113 pieArea = plotArea.width() * pieStackCount > plotArea.height() ? plotArea.height() / pieStackCount : plotArea.width();
117 QMap<QString, QColor> categoriesColor;
126 const QColor symbolColor = symbol->
color();
135 randomRamp->setTotalColorCount( categories.size() );
140 const QList<std::pair<double, double>> data = xySeries->data();
142 for (
const std::pair<double, double> &pair : data )
144 if ( !categoriesColor.contains( categories[pair.first] ) )
148 categoriesColor[categories[pair.first]] = ramp->
color( pair.first / ( categories.size() - 1 ) );
152 categoriesColor[categories[pair.first]] = symbolColor;
156 yTotal += pair.second;
160 for (
const std::pair<double, double> &pair : data )
163 if ( pieStackHorizontal )
165 center = QPointF( plotArea.x() + ( ( plotArea.width() - pieArea * pieStackCount ) / 2 + pieArea * seriesIndex + pieArea / 2 ), plotArea.y() + plotArea.height() / 2 );
169 center = QPointF( plotArea.x() + plotArea.width() / 2, plotArea.y() + ( ( plotArea.height() - pieArea * pieStackCount ) / 2 + pieArea * seriesIndex + pieArea / 2 ) );
171 QRectF boundingBox( center.x() - pieWidth / 2, center.y() - pieWidth / 2, pieWidth, pieWidth );
173 const double degreesStart = ( ySum / yTotal * 360 ) - 90;
174 const double degreesForward = pair.second / yTotal * 360;
177 path.moveTo( center );
178 path.arcTo( boundingBox, -degreesStart, -degreesForward );
182 symbol->
setColor( categoriesColor[categories[pair.first]] );
183 symbol->
renderPolygon( path.toFillPolygon(),
nullptr,
nullptr, context );
192 for (
const std::pair<double, double> &pair : data )
195 if ( pieStackHorizontal )
197 center = QPointF( plotArea.x() + ( ( plotArea.width() - pieArea * pieStackCount ) / 2 + pieArea * seriesIndex + pieArea / 2 ), plotArea.y() + plotArea.height() / 2 );
201 center = QPointF( plotArea.x() + plotArea.width() / 2, plotArea.y() + ( ( plotArea.height() - pieArea * pieStackCount ) / 2 + pieArea * seriesIndex + pieArea / 2 ) );
204 const double degreesStart = ( ySum / yTotal * 360 ) - 90;
205 const double degreesForward = pair.second / yTotal * 360;
206 const double degreesMid = ( degreesStart + ( degreesForward / 2 ) );
208 const double labelX = ( ( pieWidth + maxLabelHeight ) / 2 ) * std::cos( degreesMid * M_PI / 180 ) + center.x();
209 const double labelY = ( ( pieWidth + maxLabelHeight ) / 2 ) * std::sin( degreesMid * M_PI / 180 ) + center.y();
210 const double labelYAdjustment = degreesMid > 0 && degreesMid <= 180 ? maxLabelHeight / 2 : 0;
213 if ( degreesMid < -85 || ( degreesMid > 85 && degreesMid <= 95 ) || degreesMid > 265 )
217 else if ( degreesMid > 95 && degreesMid <= 265 )
222 switch ( mLabelType )
225 text = categories[pair.first];
229 if ( mNumericFormat )
231 text = mNumericFormat->formatDouble( pair.second, numericContext );
235 text = QString::number( pair.second );
245 QgsTextRenderer::drawText( QPointF( labelX, labelY + labelYAdjustment ), 0, horizontalAlignment, { text }, context, mLabelTextFormat );
262 if ( index < 0 || index >=
static_cast<int>( mFillSymbols.size() ) )
267 return mFillSymbols[index].get();
277 if ( index + 1 >=
static_cast<int>( mFillSymbols.size() ) )
279 mFillSymbols.resize( index + 1 );
282 mFillSymbols[index].reset( symbol );
287 if ( index < 0 || index >=
static_cast<int>( mColorRamps.size() ) )
292 return mColorRamps[index].get();
302 if ( index + 1 >=
static_cast<int>( mColorRamps.size() ) )
304 mColorRamps.resize( index + 1 );
307 mColorRamps[index].reset( ramp );
314 QDomElement fillSymbolsElement = document.createElement( u
"fillSymbols"_s );
315 for (
int i = 0; i < static_cast<int>( mFillSymbols.size() ); i++ )
317 QDomElement fillSymbolElement = document.createElement( u
"fillSymbol"_s );
318 fillSymbolElement.setAttribute( u
"index"_s, QString::number( i ) );
319 if ( mFillSymbols[i] )
323 fillSymbolsElement.appendChild( fillSymbolElement );
325 element.appendChild( fillSymbolsElement );
327 QDomElement colorRampsElement = document.createElement( u
"colorRamps"_s );
328 for (
int i = 0; i < static_cast<int>( mColorRamps.size() ); i++ )
330 QDomElement colorRampElement = document.createElement( u
"colorRamp"_s );
331 colorRampElement.setAttribute( u
"index"_s, QString::number( i ) );
332 if ( mColorRamps[i] )
336 colorRampsElement.appendChild( colorRampElement );
338 element.appendChild( colorRampsElement );
340 QDomElement textFormatElement = document.createElement( u
"textFormat"_s );
341 textFormatElement.appendChild( mLabelTextFormat.writeXml( document, context ) );
342 element.appendChild( textFormatElement );
344 if ( mNumericFormat )
346 QDomElement numericFormatElement = document.createElement( u
"numericFormat"_s );
347 mNumericFormat->writeXml( numericFormatElement, document, context );
348 element.appendChild( numericFormatElement );
360 const QDomNodeList fillSymbolsList = element.firstChildElement( u
"fillSymbols"_s ).childNodes();
361 for (
int i = 0; i < fillSymbolsList.count(); i++ )
363 const QDomElement fillSymbolElement = fillSymbolsList.at( i ).toElement();
364 const int index = fillSymbolElement.attribute( u
"index"_s, u
"-1"_s ).toInt();
367 if ( fillSymbolElement.hasChildNodes() )
369 const QDomElement symbolElement = fillSymbolElement.firstChildElement( u
"symbol"_s );
379 const QDomNodeList colorRampsList = element.firstChildElement( u
"colorRamps"_s ).childNodes();
380 for (
int i = 0; i < colorRampsList.count(); i++ )
382 const QDomElement colorRampElement = colorRampsList.at( i ).toElement();
383 const int index = colorRampElement.attribute( u
"index"_s, u
"-1"_s ).toInt();
386 if ( colorRampElement.hasChildNodes() )
388 QDomElement rampElement = colorRampElement.firstChildElement( u
"colorramp"_s );
398 const QDomElement textFormatElement = element.firstChildElement( u
"textFormat"_s );
399 mLabelTextFormat.readXml( textFormatElement, context );
401 const QDomElement numericFormatElement = element.firstChildElement( u
"numericFormat"_s );
402 if ( !numericFormatElement.isNull() )
408 mNumericFormat.reset();
434 mLabelTextFormat = format;
439 mNumericFormat.reset( format );
PieChartLabelType
Pie chart label types.
@ Categories
Category labels are drawn.
@ Values
Value labels are drawn.
@ NoLabels
Labels are not drawn.
@ Categorical
The axis represents categories.
TextHorizontalAlignment
Text horizontal alignment.
bool writeXml(QDomElement &element, QDomDocument &document, const QgsReadWriteContext &context) const override
Writes the plot's properties into an XML element.
bool readXml(const QDomElement &element, const QgsReadWriteContext &context) override
Reads the plot's properties from an XML element.
An abstract class used to encapsulate the data for a plot series.
static QgsNumericFormatRegistry * numericFormatRegistry()
Gets the registry of available numeric formats.
Abstract base class for color ramps.
virtual QColor color(double value) const =0
Returns the color corresponding to a specified value.
RAII class to pop scope from an expression context on destruction.
Single scope for storing variables and functions for use within a QgsExpressionContext.
void addVariable(const QgsExpressionContextScope::StaticVariable &variable)
Adds a variable into the context scope.
A fill symbol type, for rendering Polygon and MultiPolygon geometries.
void renderPolygon(const QPolygonF &points, const QVector< QPolygonF > *rings, const QgsFeature *f, QgsRenderContext &context, int layer=-1, bool selected=false)
Renders the symbol using the given render context.
A context for numeric formats.
void setTextFormat(const QgsTextFormat &format)
Sets the text format used for the pie chart labels.
QgsFillSymbol * fillSymbolAt(int index) const
Returns the fill symbol for the series with matching index.
void setNumericFormat(QgsNumericFormat *format)
Sets the numeric format used for the pie chart labels.
QgsColorRamp * colorRampAt(int index) const
Returns the color ramp for the series with matching index.
void setLabelType(Qgis::PieChartLabelType type)
Sets the pie chart label type.
bool readXml(const QDomElement &element, const QgsReadWriteContext &context) override
Reads the plot's properties from an XML element.
bool writeXml(QDomElement &element, QDomDocument &document, const QgsReadWriteContext &context) const override
Writes the plot's properties into an XML element.
static QgsPieChartPlot * create()
Returns a new pie chart.
void setColorRampAt(int index, QgsColorRamp *ramp)
Sets the color ramp for the series with matching index.
void setFillSymbolAt(int index, QgsFillSymbol *symbol)
Sets the fill symbol to use for the series with matching index.
QString type() const override
Returns the plot's type.
void renderContent(QgsRenderContext &context, QgsPlotRenderContext &plotContext, const QRectF &plotArea, const QgsPlotData &plotData=QgsPlotData()) override
Renders the plot content.
static QgsVectorLayerAbstractPlotDataGatherer * createDataGatherer(QgsPlot *plot)
Returns a new data gatherer for a given pie chart plot.
Encapsulates one or more plot series.
QStringList categories() const
Returns the name of the series' categories.
QList< QgsAbstractPlotSeries * > series() const
Returns the list of series forming the plot data.
static QgsNumericFormat * pieChartNumericFormat()
Returns the default color ramp to use for pie charts.
static QgsColorRamp * pieChartColorRamp()
Returns the default color ramp to use for pie charts.
static QgsFillSymbol * pieChartFillSymbol()
Returns the default fill symbol to use for pie charts.
Contains information about the context of a plot rendering operation.
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.
QPainter * painter()
Returns the destination QPainter for the render operation.
QgsExpressionContext & expressionContext()
Gets the expression context.
static std::unique_ptr< QgsColorRamp > loadColorRamp(QDomElement &element)
Creates a color ramp from the settings encoded in an XML element.
static std::unique_ptr< QgsSymbol > loadSymbol(const QDomElement &element, const QgsReadWriteContext &context)
Attempts to load a symbol from a DOM element.
static QDomElement saveSymbol(const QString &symbolName, const QgsSymbol *symbol, QDomDocument &doc, const QgsReadWriteContext &context)
Writes a symbol definition to XML.
static QDomElement saveColorRamp(const QString &name, const QgsColorRamp *ramp, QDomDocument &doc)
Encodes a color ramp's settings to an XML element.
static double estimateMaxSymbolBleed(QgsSymbol *symbol, const QgsRenderContext &context)
Returns the maximum estimated bleed for the symbol.
void stopRender(QgsRenderContext &context)
Ends the rendering process.
void setColor(const QColor &color) const
Sets the color for the symbol.
QColor color() const
Returns the symbol's color.
void startRender(QgsRenderContext &context, const QgsFields &fields=QgsFields())
Begins the rendering process for the symbol.
Container for all settings relating to text rendering.
static void drawText(const QRectF &rect, double rotation, Qgis::TextHorizontalAlignment alignment, const QStringList &textLines, QgsRenderContext &context, const QgsTextFormat &format, bool drawAsOutlines=true, Qgis::TextVerticalAlignment vAlignment=Qgis::TextVerticalAlignment::Top, Qgis::TextRendererFlags flags=Qgis::TextRendererFlags(), Qgis::TextLayoutMode mode=Qgis::TextLayoutMode::Rectangle)
Draws text within a rectangle using the specified settings.
static double textHeight(const QgsRenderContext &context, const QgsTextFormat &format, const QStringList &textLines, Qgis::TextLayoutMode mode=Qgis::TextLayoutMode::Point, QFontMetricsF *fontMetrics=nullptr, Qgis::TextRendererFlags flags=Qgis::TextRendererFlags(), double maxLineWidth=0)
Returns the height of a text based on a given format.
An abstract vector layer plot data gatherer base class.
An vector layer plot data gatherer class for XY series.
Encapsulates the data for an XY plot series.
T qgsEnumKeyToValue(const QString &key, const T &defaultValue, bool tryValueAsKey=true, bool *returnOk=nullptr)
Returns the value corresponding to the given key of an enum.
QString qgsEnumValueToKey(const T &value, bool *returnOk=nullptr)
Returns the value for the given key of an enum.
Single variable definition for use within a QgsExpressionContextScope.