在前面的图表中,我们使用的坐标系都是直角坐标系(也称笛卡尔坐标系), 但是有些数据序列,使用极坐标系来显示更合理(比如常见的雷达图)。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极坐标系演示
前一篇: 实战PyQt5: 154-QChart图表之多坐标轴图表