QGIS API Documentation 3.99.0-Master (21b3aa880ba)
Loading...
Searching...
No Matches
qgsbarchartplot.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgsbarchartplot.cpp
3 -------------------
4 begin : June 2025
5 copyright : (C) 2025 by Mathieu
6 email : mathieu at opengis dot ch
7 ***************************************************************************/
8
9/***************************************************************************
10 * *
11 * This program is free software; you can redistribute it and/or modify *
12 * it under the terms of the GNU General Public License as published by *
13 * the Free Software Foundation; either version 2 of the License, or *
14 * (at your option) any later version. *
15 * *
16 ***************************************************************************/
17
18#include "qgsbarchartplot.h"
19
21#include "qgssymbol.h"
22#include "qgssymbollayer.h"
23#include "qgssymbollayerutils.h"
25
30
31void QgsBarChartPlot::renderContent( QgsRenderContext &context, QgsPlotRenderContext &, const QRectF &plotArea, const QgsPlotData &plotData )
32{
33 if ( mFillSymbols.empty() )
34 {
35 return;
36 }
37
38 const QList<QgsAbstractPlotSeries *> seriesList = plotData.series();
39 if ( seriesList.isEmpty() )
40 {
41 return;
42 }
43
44 const QStringList categories = plotData.categories();
45 switch ( xAxis().type() )
46 {
48 if ( categories.isEmpty() )
49 {
50 return;
51 }
52 break;
53
55 break;
56 }
57
58 QgsExpressionContextScope *chartScope = new QgsExpressionContextScope( QStringLiteral( "chart" ) );
59 const QgsExpressionContextScopePopper scopePopper( context.expressionContext(), chartScope );
60
61 context.painter()->save();
62 context.painter()->setClipRect( plotArea );
63
64 double minX = xMinimum();
65 double maxX = xMaximum();
66 double minY = yMinimum();
67 double maxY = yMaximum();
68 double majorIntervalX = xAxis().gridIntervalMajor();
69 double minorIntervalX = xAxis().gridIntervalMinor();
70 double labelIntervalX = xAxis().labelInterval();
71 double majorIntervalY = yAxis().gridIntervalMajor();
72 double minorIntervalY = yAxis().gridIntervalMinor();
73 double labelIntervalY = yAxis().labelInterval();
74 Qgs2DXyPlot::applyDataDefinedProperties( context, minX, maxX, minY, maxY, majorIntervalX, minorIntervalX, labelIntervalX, majorIntervalY, minorIntervalY, labelIntervalY );
75
76 const double xScale = plotArea.width() / ( maxX - minX );
77 const double yScale = plotArea.height() / ( maxY - minY );
78 const double categoriesWidth = plotArea.width() / categories.size();
79 const double valuesWidth = plotArea.width() * ( minorIntervalX / ( maxX - minX ) );
80 const double barsWidth = xAxis().type() == Qgis::PlotAxisType::Categorical ? categoriesWidth / 2 : valuesWidth / 2;
81 const double barWidth = barsWidth / seriesList.size();
82 int seriesIndex = 0;
83 for ( const QgsAbstractPlotSeries *series : seriesList )
84 {
85 QgsFillSymbol *symbol = fillSymbolAt( seriesIndex % mFillSymbols.size() );
86 if ( !symbol )
87 {
88 continue;
89 }
90 symbol->startRender( context );
91
92 const double barStartAdjustment = -( barsWidth / 2 ) + barWidth * seriesIndex;
93 if ( const QgsXyPlotSeries *xySeries = dynamic_cast<const QgsXyPlotSeries *>( series ) )
94 {
95 const QList<std::pair<double, double>> data = xySeries->data();
96 for ( const std::pair<double, double> &pair : data )
97 {
98 double x = 0;
99 switch ( xAxis().type() )
100 {
102 if ( pair.first < 0 || pair.first >= categories.size() )
103 {
104 continue;
105 }
106 x = ( categoriesWidth * pair.first ) + ( categoriesWidth / 2 ) + barStartAdjustment;
107 chartScope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "chart_category" ), categories[pair.first], true ) );
108 break;
109
111 x = ( pair.first - minX ) * xScale + barStartAdjustment;
112 break;
113 }
114
115 double y = ( pair.second - minY ) * yScale;
116
117 const double zero = ( 0.0 - minY ) * yScale;
118 const QPoint topLeft( plotArea.left() + x,
119 plotArea.y() + plotArea.height() - y );
120 const QPoint bottomRight( plotArea.left() + x + barWidth,
121 plotArea.y() + plotArea.height() - zero );
122
123 chartScope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "chart_value" ), pair.second, true ) );
124 symbol->renderPolygon( QPolygonF( QRectF( topLeft, bottomRight ) ), nullptr, nullptr, context );
125 }
126 }
127
128 symbol->stopRender( context );
129 seriesIndex++;
130 }
131
132 context.painter()->restore();
133}
134
136{
137 if ( index < 0 || index >= static_cast<int>( mFillSymbols.size() ) )
138 {
139 return nullptr;
140 }
141
142 return mFillSymbols[index].get();
143}
144
146{
147 if ( index < 0 )
148 {
149 return;
150 }
151
152 if ( index + 1 >= static_cast<int>( mFillSymbols.size() ) )
153 {
154 mFillSymbols.resize( index + 1 );
155 }
156
157 mFillSymbols[index].reset( symbol );
158}
159
160bool QgsBarChartPlot::writeXml( QDomElement &element, QDomDocument &document, const QgsReadWriteContext &context ) const
161{
162 Qgs2DXyPlot::writeXml( element, document, context );
163
164 QDomElement fillSymbolsElement = document.createElement( QStringLiteral( "fillSymbols" ) );
165 for ( int i = 0; i < static_cast<int>( mFillSymbols.size() ); i++ )
166 {
167 QDomElement fillSymbolElement = document.createElement( QStringLiteral( "fillSymbol" ) );
168 fillSymbolElement.setAttribute( QStringLiteral( "index" ), QString::number( i ) );
169 if ( mFillSymbols[i] )
170 {
171 fillSymbolElement.appendChild( QgsSymbolLayerUtils::saveSymbol( QString(), mFillSymbols[i].get(), document, context ) );
172 }
173 fillSymbolsElement.appendChild( fillSymbolElement );
174 }
175 element.appendChild( fillSymbolsElement );
176
177 return true;
178}
179
180bool QgsBarChartPlot::readXml( const QDomElement &element, const QgsReadWriteContext &context )
181{
182 Qgs2DXyPlot::readXml( element, context );
183
184 const QDomNodeList fillSymbolsList = element.firstChildElement( QStringLiteral( "fillSymbols" ) ).childNodes();
185 for ( int i = 0; i < fillSymbolsList.count(); i++ )
186 {
187 const QDomElement fillSymbolElement = fillSymbolsList.at( i ).toElement();
188 const int index = fillSymbolElement.attribute( QStringLiteral( "index" ), QStringLiteral( "-1" ) ).toInt();
189 if ( index >= 0 )
190 {
191 if ( fillSymbolElement.hasChildNodes() )
192 {
193 const QDomElement symbolElement = fillSymbolElement.firstChildElement( QStringLiteral( "symbol" ) );
194 setFillSymbolAt( index, QgsSymbolLayerUtils::loadSymbol< QgsFillSymbol >( symbolElement, context ).release() );
195 }
196 else
197 {
198 setFillSymbolAt( index, nullptr );
199 }
200 }
201 }
202
203 return true;
204}
205
210
212{
213 QgsBarChartPlot *chart = dynamic_cast<QgsBarChartPlot *>( plot );
214 if ( !chart )
215 {
216 return nullptr;
217 }
218
219 return new QgsVectorLayerXyPlotDataGatherer( chart->xAxis().type() );
220}
@ Categorical
The axis represents categories.
Definition qgis.h:3336
@ Interval
The axis represents a range of values.
Definition qgis.h:3335
double yMaximum() const
Returns the maximum value of the y axis.
Definition qgsplot.h:742
double xMinimum() const
Returns the minimum value of the x axis.
Definition qgsplot.h:700
bool readXml(const QDomElement &element, const QgsReadWriteContext &context) override
Reads the plot's properties from an XML element.
Definition qgsplot.cpp:390
void applyDataDefinedProperties(QgsRenderContext &context, double &minX, double &maxX, double &minY, double &maxY, double &majorIntervalX, double &minorIntervalX, double &labelIntervalX, double &majorIntervalY, double &minorIntervalY, double &labelIntervalY) const
Applies 2D XY plot data-defined properties.
Definition qgsplot.cpp:1052
QgsPlotAxis & yAxis()
Returns a reference to the plot's y axis.
Definition qgsplot.h:770
QgsPlotAxis & xAxis()
Returns a reference to the plot's x axis.
Definition qgsplot.h:756
double yMinimum() const
Returns the minimum value of the y axis.
Definition qgsplot.h:714
bool writeXml(QDomElement &element, QDomDocument &document, const QgsReadWriteContext &context) const override
Writes the plot's properties into an XML element.
Definition qgsplot.cpp:364
double xMaximum() const
Returns the maximum value of the x axis.
Definition qgsplot.h:728
An abstract class used to encapsulate the data for a plot series.
Definition qgsplot.h:204
QString type() const override
Returns the plot's type.
void setFillSymbolAt(int index, QgsFillSymbol *symbol)
Sets the fill symbol to use for the series with matching index.
void renderContent(QgsRenderContext &context, QgsPlotRenderContext &plotContext, const QRectF &plotArea, const QgsPlotData &plotData=QgsPlotData()) override
Renders the plot content.
bool readXml(const QDomElement &element, const QgsReadWriteContext &context) override
Reads the plot's properties from an XML element.
static QgsVectorLayerAbstractPlotDataGatherer * createDataGatherer(QgsPlot *plot)
Returns a new data gatherer for a given bar chart plot.
QgsFillSymbol * fillSymbolAt(int index) const
Returns the fill symbol for the series with matching index.
bool writeXml(QDomElement &element, QDomDocument &document, const QgsReadWriteContext &context) const override
Writes the plot's properties into an XML element.
static QgsBarChartPlot * create()
Returns a new bar chart.
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.
double gridIntervalMinor() const
Returns the interval of minor grid lines for the axis.
Definition qgsplot.h:389
double gridIntervalMajor() const
Returns the interval of major grid lines for the axis.
Definition qgsplot.h:403
Qgis::PlotAxisType type() const
Returns the axis type.
Definition qgsplot.cpp:103
double labelInterval() const
Returns the interval of labels for the axis.
Definition qgsplot.h:417
Encapsulates one or more plot series.
Definition qgsplot.h:300
QStringList categories() const
Returns the name of the series' categories.
Definition qgsplot.cpp:1300
QList< QgsAbstractPlotSeries * > series() const
Returns the list of series forming the plot data.
Definition qgsplot.cpp:1281
static QgsFillSymbol * barChartFillSymbol()
Returns the default fill symbol to use for bar charts.
Definition qgsplot.cpp:1208
Contains information about the context of a plot rendering operation.
Definition qgsplot.h:184
QgsPlot()=default
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< 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.
void stopRender(QgsRenderContext &context)
Ends the rendering process.
void startRender(QgsRenderContext &context, const QgsFields &fields=QgsFields())
Begins the rendering process for the symbol.
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.
Definition qgsplot.h:258
Single variable definition for use within a QgsExpressionContextScope.