39 if ( mFillSymbols.empty() )
44 const QList<QgsAbstractPlotSeries *> seriesList = plotData.
series();
45 if ( seriesList.isEmpty() || plotData.
categories().isEmpty() )
50 const QStringList categories = plotData.
categories();
51 double maxLabelHeight = 0;
56 for (
const QString &category : categories )
72 const QList<std::pair<double, double>> data = xySeries->data();
73 for (
const std::pair<double, double> &pair : data )
77 text = mNumericFormat->formatDouble( pair.second, numericContext );
81 text = QString::number( pair.second );
98 context.
painter()->setClipRect( plotArea );
100 const bool pieStackHorizontal = plotArea.width() >= plotArea.height();
101 const double pieStackCount = seriesList.size();
103 if ( pieStackHorizontal )
105 pieArea = plotArea.height() * pieStackCount > plotArea.width() ? plotArea.width() / pieStackCount : plotArea.height();
109 pieArea = plotArea.width() * pieStackCount > plotArea.height() ? plotArea.height() / pieStackCount : plotArea.width();
113 QMap<QString, QColor> categoriesColor;
122 const QColor symbolColor = symbol->
color();
131 randomRamp->setTotalColorCount( categories.size() );
136 const QList<std::pair<double, double>> data = xySeries->data();
138 for (
const std::pair<double, double> &pair : data )
140 if ( !categoriesColor.contains( categories[pair.first] ) )
144 categoriesColor[categories[pair.first]] = ramp->
color( pair.first / ( categories.size() - 1 ) );
148 categoriesColor[categories[pair.first]] = symbolColor;
152 yTotal += pair.second;
156 for (
const std::pair<double, double> &pair : data )
159 if ( pieStackHorizontal )
161 center = QPointF( plotArea.x() + ( ( plotArea.width() - pieArea * pieStackCount ) / 2 + pieArea * seriesIndex + pieArea / 2 ), plotArea.y() + plotArea.height() / 2 );
165 center = QPointF( plotArea.x() + plotArea.width() / 2, plotArea.y() + ( ( plotArea.height() - pieArea * pieStackCount ) / 2 + pieArea * seriesIndex + pieArea / 2 ) );
167 QRectF boundingBox( center.x() - pieWidth / 2, center.y() - pieWidth / 2, pieWidth, pieWidth );
169 const double degreesStart = ( ySum / yTotal * 360 ) - 90;
170 const double degreesForward = pair.second / yTotal * 360;
173 path.moveTo( center );
174 path.arcTo( boundingBox, -degreesStart, -degreesForward );
178 symbol->
setColor( categoriesColor[categories[pair.first]] );
179 symbol->
renderPolygon( path.toFillPolygon(),
nullptr,
nullptr, context );
188 for (
const std::pair<double, double> &pair : data )
191 if ( pieStackHorizontal )
193 center = QPointF( plotArea.x() + ( ( plotArea.width() - pieArea * pieStackCount ) / 2 + pieArea * seriesIndex + pieArea / 2 ), plotArea.y() + plotArea.height() / 2 );
197 center = QPointF( plotArea.x() + plotArea.width() / 2, plotArea.y() + ( ( plotArea.height() - pieArea * pieStackCount ) / 2 + pieArea * seriesIndex + pieArea / 2 ) );
200 const double degreesStart = ( ySum / yTotal * 360 ) - 90;
201 const double degreesForward = pair.second / yTotal * 360;
202 const double degreesMid = ( degreesStart + ( degreesForward / 2 ) );
204 const double labelX = ( ( pieWidth + maxLabelHeight ) / 2 ) * std::cos( degreesMid * M_PI / 180 ) + center.x();
205 const double labelY = ( ( pieWidth + maxLabelHeight ) / 2 ) * std::sin( degreesMid * M_PI / 180 ) + center.y();
206 const double labelYAdjustment = degreesMid > 0 && degreesMid <= 180 ? maxLabelHeight / 2 : 0;
209 if ( degreesMid < -85 || ( degreesMid > 85 && degreesMid <= 95 ) || degreesMid > 265 )
213 else if ( degreesMid > 95 && degreesMid <= 265 )
218 switch ( mLabelType )
221 text = categories[pair.first];
225 if ( mNumericFormat )
227 text = mNumericFormat->formatDouble( pair.second, numericContext );
231 text = QString::number( pair.second );
241 QgsTextRenderer::drawText( QPointF( labelX, labelY + labelYAdjustment ), 0, horizontalAlignment, { text }, context, mLabelTextFormat );
258 if ( index < 0 || index >=
static_cast<int>( mFillSymbols.size() ) )
263 return mFillSymbols[index].get();
273 if ( index + 1 >=
static_cast<int>( mFillSymbols.size() ) )
275 mFillSymbols.resize( index + 1 );
278 mFillSymbols[index].reset( symbol );
283 if ( index < 0 || index >=
static_cast<int>( mColorRamps.size() ) )
288 return mColorRamps[index].get();
298 if ( index + 1 >=
static_cast<int>( mColorRamps.size() ) )
300 mColorRamps.resize( index + 1 );
303 mColorRamps[index].reset( ramp );
310 QDomElement fillSymbolsElement = document.createElement( QStringLiteral(
"fillSymbols" ) );
311 for (
int i = 0; i < static_cast<int>( mFillSymbols.size() ); i++ )
313 QDomElement fillSymbolElement = document.createElement( QStringLiteral(
"fillSymbol" ) );
314 fillSymbolElement.setAttribute( QStringLiteral(
"index" ), QString::number( i ) );
315 if ( mFillSymbols[i] )
319 fillSymbolsElement.appendChild( fillSymbolElement );
321 element.appendChild( fillSymbolsElement );
323 QDomElement colorRampsElement = document.createElement( QStringLiteral(
"colorRamps" ) );
324 for (
int i = 0; i < static_cast<int>( mColorRamps.size() ); i++ )
326 QDomElement colorRampElement = document.createElement( QStringLiteral(
"colorRamp" ) );
327 colorRampElement.setAttribute( QStringLiteral(
"index" ), QString::number( i ) );
328 if ( mColorRamps[i] )
332 colorRampsElement.appendChild( colorRampElement );
334 element.appendChild( colorRampsElement );
336 QDomElement textFormatElement = document.createElement( QStringLiteral(
"textFormat" ) );
337 textFormatElement.appendChild( mLabelTextFormat.writeXml( document, context ) );
338 element.appendChild( textFormatElement );
340 if ( mNumericFormat )
342 QDomElement numericFormatElement = document.createElement( QStringLiteral(
"numericFormat" ) );
343 mNumericFormat->writeXml( numericFormatElement, document, context );
344 element.appendChild( numericFormatElement );
347 element.setAttribute( QStringLiteral(
"pieChartLabelType" ),
qgsEnumValueToKey( mLabelType ) );
356 const QDomNodeList fillSymbolsList = element.firstChildElement( QStringLiteral(
"fillSymbols" ) ).childNodes();
357 for (
int i = 0; i < fillSymbolsList.count(); i++ )
359 const QDomElement fillSymbolElement = fillSymbolsList.at( i ).toElement();
360 const int index = fillSymbolElement.attribute( QStringLiteral(
"index" ), QStringLiteral(
"-1" ) ).toInt();
363 if ( fillSymbolElement.hasChildNodes() )
365 const QDomElement symbolElement = fillSymbolElement.firstChildElement( QStringLiteral(
"symbol" ) );
375 const QDomNodeList colorRampsList = element.firstChildElement( QStringLiteral(
"colorRamps" ) ).childNodes();
376 for (
int i = 0; i < colorRampsList.count(); i++ )
378 const QDomElement colorRampElement = colorRampsList.at( i ).toElement();
379 const int index = colorRampElement.attribute( QStringLiteral(
"index" ), QStringLiteral(
"-1" ) ).toInt();
382 if ( colorRampElement.hasChildNodes() )
384 QDomElement rampElement = colorRampElement.firstChildElement( QStringLiteral(
"colorramp" ) );
394 const QDomElement textFormatElement = element.firstChildElement( QStringLiteral(
"textFormat" ) );
395 mLabelTextFormat.readXml( textFormatElement, context );
397 const QDomElement numericFormatElement = element.firstChildElement( QStringLiteral(
"numericFormat" ) );
398 if ( !numericFormatElement.isNull() )
404 mNumericFormat.reset();
430 mLabelTextFormat = format;
435 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.