Donut Chart Breakdown Example#
This example shows how to use create a donut breakdown chart using QPieSeries
API.
Running the Example#
To run the example from Qt Creator , open the Welcome mode and select the example from Examples. For more information, visit Building and Running an Example.
Creating Donut Breakdown Charts#
Let’s start by defining some data for the chart.
# Graph is based on data of 'Total consumption of energy increased by 10 per cent in 2010' # Statistics Finland, 13 December 2011 # http://www.stat.fi/til/ekul/2010/ekul_2010_2011-12-13_tie_001_en.html series1 = QPieSeries() series1.setName("Fossil fuels") series1.append("Oil", 353295) series1.append("Coal", 188500) series1.append("Natural gas", 148680) series1.append("Peat", 94545) series2 = QPieSeries() series2.setName("Renewables") series2.append("Wood fuels", 319663) series2.append("Hydro power", 45875) series2.append("Wind power", 1060) series3 = QPieSeries() series3.setName("Others") series3.append("Nuclear energy", 238789) series3.append("Import energy", 37802) series3.append("Other", 32441)
Then we create a chart where we add the data. Note that this is our own chart derived from QChart
.
donutBreakdown = DonutBreakdownChart() donutBreakdown.setAnimationOptions(QChart.AllAnimations) donutBreakdown.setTitle("Total consumption of energy in Finland 2010") donutBreakdown.legend().setAlignment(Qt.AlignRight) donutBreakdown.addBreakdownSeries(series1, Qt.red) donutBreakdown.addBreakdownSeries(series2, Qt.darkGreen) donutBreakdown.addBreakdownSeries(series3, Qt.darkBlue)
Our own chart works in such a way that we create a main series in the constructor we create a main series, which aggregates the data provided by the breakdown series. This is the piechart in the center.
DonutBreakdownChart.DonutBreakdownChart(QGraphicsItem parent, Qt.WindowFlags wFlags) QChart.__init__(self, .ChartTypeCartesian, parent, wFlags) # create the series for main center pie m_mainSeries = QPieSeries() m_mainSeries.setPieSize(0.7) QChart.addSeries(m_mainSeries)
When a breakdown series is added the data is used to create a slice in the main series and the breakdown series itself is used to create a segment of a donut positioned so that it is aligned with the corresponding slice in the main series.
def addBreakdownSeries(self, breakdownSeries, color): font = QFont("Arial", 8) # add breakdown series as a slice to center pie mainSlice = MainSlice(breakdownSeries) mainSlice.setName(breakdownSeries.name()) mainSlice.setValue(breakdownSeries.sum()) m_mainSeries.append(mainSlice) # customize the slice mainSlice.setBrush(color) mainSlice.setLabelVisible() mainSlice.setLabelColor(Qt.white) mainSlice.setLabelPosition(QPieSlice.LabelInsideHorizontal) mainSlice.setLabelFont(font) # position and customize the breakdown series breakdownSeries.setPieSize(0.8) breakdownSeries.setHoleSize(0.7) breakdownSeries.setLabelsVisible() slices = breakdownSeries.slices() for slice in slices: color = color.lighter(115) slice.setBrush(color) slice.setLabelFont(font) # add the series to the chart QChart.addSeries(breakdownSeries) # recalculate breakdown donut segments recalculateAngles() # update customize legend markers updateLegendMarkers()
Here’s how the start and end angles for the donut segments are calculated.
def recalculateAngles(self): angle = 0 slices = m_mainSeries.slices() for slice in slices: breakdownSeries = MainSlice (slice).breakdownSeries() breakdownSeries.setPieStartAngle(angle) angle += slice.percentage() * 360.0 # full pie is 360.0 breakdownSeries.setPieEndAngle(angle)
The legend markers are customized to show the breakdown percentage. The markers for the main level slices are hidden.
def updateLegendMarkers(self): # go through all markers allseries = series() for series in allseries: markers = legend().markers(series) for marker in markers: pieMarker = QPieLegendMarker (marker) if (series == m_mainSeries) { # hide markers from main series pieMarker.setVisible(False) else: # modify markers from breakdown series pieMarker.setLabel(QString("%1 %2%") .arg(pieMarker.slice().label()) .arg(pieMarker.slice().percentage() * 100, 0, 'f', 2)) pieMarker.setFont(QFont("Arial", 8))
Instead the main level slices show the percentage on the label.
def __init__(self, breakdownSeries, parent): QPieSlice.__init__(self, parent) m_breakdownSeries(breakdownSeries) connect(self, MainSlice::percentageChanged, self, MainSlice::updateLabel) def updateLabel(self): self.setLabel(QString("%1 %2%").arg(m_name).arg(percentage() * 100, 0, 'f', 2))
Now that we have our chart defined, we can finally create a QChartView
and show the chart.
window = QMainWindow() chartView = QChartView(donutBreakdown) chartView.setRenderHint(QPainter.Antialiasing) window.setCentralWidget(chartView) window.resize(800, 500) window.show()