在前面的图表中,我们使用的坐标系都是直角坐标系(也称笛卡尔坐标系), 但是有些数据序列,使用极坐标系来显示更合理(比如常见的雷达图)。QChart中,提供QPolarChart来实现用极坐标系显示的图表。
QPolarChart在极坐标图中显示数据。极坐标图在圆形图中显示数据,其数据基于图形中心极点的距离和与水平方向的夹角来确定。
QChart中的极坐标支持折线,样条曲线,面积和散点图表序列,它也支持所有的轴类型,而且每个轴多可以作为径向轴(radial axis)或者角度轴(angular axis)。
在极坐标系中,角度轴QValueAxis上的第一个和最后一个刻度线位于0/360度处。
如果图表数据序列中两个连续点之间的角距离大于180度,则连接两个点的任何直线将变得毫无意义,因此将不会绘制。而是会在图表的中心绘制一条线。因此,在显示直线,样条曲线或区域序列时,必须相应地选择轴范围。
极坐标图在相同位置绘制相同方向的所有轴,因此使用多个相同方向的轴可能会造成混淆,除非多余的轴仅用于自定义网格。例如,可以显示带有辅助阴影的QCategoryAxis的突出显示范围,或提供带有辅助QValueAxis的未标记子刻度等。
QPolarChart常用函数:
示例显示了如何创建具有多个不同系列的简单极坐标图。显示了如何实现极坐标图的滚动和缩放,以及直观地展示了极坐标图和笛卡尔图如何相互关联。完整代码如下:
- import sys
- from PyQt5.QtCore import Qt, QPointF
- from PyQt5.QtGui import QPainter, QBrush, QColor
- from PyQt5.QtWidgets import QApplication, QMainWindow, QGraphicsView
- from PyQt5.QtChart import (QChart, QChartView, QPolarChart, QScatterSeries,
- QSplineSeries, QLineSeries, QAreaSeries, QValueAxis)
-
- class MyChartView(QChartView):
- def __init__(self, parent = None):
- super(MyChartView, self).__init__(parent)
-
- def keyPressEvent(self, event):
-
- if event.key() == Qt.Key_Plus:
- self.chart().zoomIn()
- elif event.key() == Qt.Key_Minus:
- self.chart().zoomOut()
- elif event.key() == Qt.Key_Left:
- self.chart().scroll(-1.0, 0)
- elif event.key() == Qt.Key_Right:
- self.chart().scroll(1.0, 0)
- elif event.key() == Qt.Key_Up:
- self.chart().scroll(0, 1.0)
- elif event.key() == Qt.Key_Down:
- self.chart().scroll(0, -1.0)
- elif event.key() == Qt.Key_Space:
- self.switchChartType()
- else:
- QGraphicsView.keyPressEvent(self, event)
-
- def switchChartType(self):
- oldChart = self.chart()
-
- if oldChart.chartType() == QChart.ChartTypeCartesian:
- newChart = QPolarChart()
- else:
- newChart = QChart()
-
- axisRanges = []
-
- #将图表序列和轴从旧图表移动到新图表
- seriesList = oldChart.series()
- axisList = oldChart.axes()
-
- for axis in axisList:
- axisRanges.append(QPointF(axis.min(), axis.max()))
-
- for series in seriesList:
- oldChart.removeSeries(series)
-
- for axis in axisList:
- oldChart.removeAxis(axis)
- align = axis.alignment()
- #bug fix
- if oldChart.chartType() == QChart.ChartTypeCartesian:
- if align == Qt.AlignBottom:
- align = QPolarChart.PolarOrientationAngular
- else:
- align = QPolarChart.PolarOrientationRadial
-
- newChart.addAxis(axis, align)
-
- for series in seriesList:
- newChart.addSeries(series)
- for axis in axisList:
- series.attachAxis(axis)
-
- for index, axis in enumerate(axisList):
- axis.setRange(axisRanges[index].x(), axisRanges[index].y())
-
- newChart.setTitle(oldChart.title())
- self.setChart(newChart)
- del oldChart
-
- class DemoPolarChart(QMainWindow):
- def __init__(self, parent=None):
- super(DemoPolarChart, self).__init__(parent)
-
- # 设置窗口标题
- self.setWindowTitle('实战 Qt for Python: 极坐标演示')
- # 设置窗口大小
- self.resize(640, 480)
-
- self.createChart()
-
- def createChart(self):
-
- angularMin = -100
- angularMax = 100
- radialMin = -100
- radialMax = 100
-
- series1 = QScatterSeries()
- series1.setName('散点图')
- for i in range(angularMin, angularMax, 10):
- series1.append(i, (i / radialMax) * radialMax + 8.0)
-
- series2 = QSplineSeries()
- series2.setName('样条曲线')
- for i in range(angularMin, angularMax, 10):
- series2.append(i, (i / radialMax) * radialMax)
-
- series3 = QLineSeries()
- series3.setName('星星外边界线')
- ad = (angularMax - angularMin) / 8
- rd = (radialMax - radialMin) / 3 * 1.3
- series3.append(angularMin, radialMax)
- series3.append(angularMin + ad*1, radialMin + rd)
- series3.append(angularMin + ad*2, radialMax)
- series3.append(angularMin + ad*3, radialMin + rd)
- series3.append(angularMin + ad*4, radialMax)
- series3.append(angularMin + ad*5, radialMin + rd)
- series3.append(angularMin + ad*6, radialMax)
- series3.append(angularMin + ad*7, radialMin + rd)
- series3.append(angularMin + ad*8, radialMax)
-
- series4 = QLineSeries()
- series4.setName('星星内边界线')
- ad = (angularMax - angularMin) / 8
- rd = (radialMax - radialMin) / 3
- series4.append(angularMin, radialMax)
- series4.append(angularMin + ad*1, radialMin + rd)
- series4.append(angularMin + ad*2, radialMax)
- series4.append(angularMin + ad*3, radialMin + rd)
- series4.append(angularMin + ad*4, radialMax)
- series4.append(angularMin + ad*5, radialMin + rd)
- series4.append(angularMin + ad*6, radialMax)
- series4.append(angularMin + ad*7, radialMin + rd)
- series4.append(angularMin + ad*8, radialMax)
-
- series5 = QAreaSeries()
- series5.setName('星星区域')
- series5.setUpperSeries(series3)
- series5.setLowerSeries(series4)
- series5.setOpacity(0.5)
-
- #创建图表
- chart = QPolarChart()
- chart.addSeries(series1)
- chart.addSeries(series2)
- chart.addSeries(series3)
- chart.addSeries(series4)
- chart.addSeries(series5)
- chart.setTitle('使用箭头键可以滚动,使用+/-键可以缩放,使用空格键可以切换图表类型.')
-
- angularAxis = QValueAxis()
- angularAxis.setTickCount(9) #第一个和最后一个刻度在0/360角度上同一位置
- angularAxis.setLabelFormat('%.1f')
- angularAxis.setShadesVisible(True)
- angularAxis.setShadesBrush(QBrush(QColor(249, 249, 255)))
- chart.addAxis(angularAxis, QPolarChart.PolarOrientationAngular)
-
- radialAxis = QValueAxis()
- radialAxis.setTickCount(9)
- radialAxis.setLabelFormat('%d')
- chart.addAxis(radialAxis, QPolarChart.PolarOrientationRadial)
-
- series1.attachAxis(radialAxis)
- series1.attachAxis(angularAxis)
- series2.attachAxis(radialAxis)
- series2.attachAxis(angularAxis)
- series3.attachAxis(radialAxis)
- series3.attachAxis(angularAxis)
- series4.attachAxis(radialAxis)
- series4.attachAxis(angularAxis)
- series5.attachAxis(radialAxis)
- series5.attachAxis(angularAxis)
-
- radialAxis.setRange(radialMin, radialMax)
- angularAxis.setRange(angularMin, angularMax)
-
- #图表视图
- chartView = MyChartView()
- chartView.setChart(chart)
- chartView.setRenderHint(QPainter.Antialiasing)
-
- self.setCentralWidget(chartView)
-
-
- if __name__ == '__main__':
- app = QApplication(sys.argv)
- window = DemoPolarChart()
- window.show()
- sys.exit(app.exec())
运行结果如下图:

QChart极坐标系演示