1. 前言
突然好奇极坐标图(雷达图)是怎么实现的,就查了一下资料,发现有几种实现方法:一是QtChart实现;二是QCustomPlot实现;三是自绘。前两者都给了示例,所以我就学了学,后者自绘我尽力吧。
2. 说明和代码
QtChart实现图表一般要设置三部分:模型、数据、轴,如果要实现极坐标图,三者分别为:
- 模型:必须为QPolarChart;
- 数据:想要什么样的数据表达形式,可选择不同的类来存储数据,比如散点选择QScatterSeries、直线选择QLineSeries等;
- 轴:轴也是根据表现形式的不同选择不同的轴类,都是继承QAbstractAxis,最常用到的是QValueAxis。
2.1. 一般结构代码
这里先给个示例代码:
const qreal angularMin = -100;
const qreal angularMax = 100;
const qreal radialMin = -100;
const qreal radialMax = 100;
//数据
QScatterSeries *series1 = new QScatterSeries();
series1->setName("scatter");
for (int i = angularMin; i <= angularMax; i += 10)
series1->append(i, (i / radialMax) * radialMax + 8.0);
//模型
QPolarChart *chart = new QPolarChart();
chart->addSeries(series1);
//轴
QValueAxis *angularAxis = new QValueAxis();
angularAxis->setTickCount(9); // First and last ticks are co-located on 0/360 angle.
angularAxis->setLabelFormat("%.1f");
angularAxis->setShadesVisible(true);
angularAxis->setShadesBrush(QBrush(QColor(249, 249, 255)));
chart->addAxis(angularAxis, QPolarChart::PolarOrientationAngular);
QValueAxis *radialAxis = new QValueAxis();
radialAxis->setTickCount(9);
radialAxis->setLabelFormat("%d");
chart->addAxis(radialAxis, QPolarChart::PolarOrientationRadial);
series1->attachAxis(radialAxis);
series1->attachAxis(angularAxis);
radialAxis->setRange(radialMin, radialMax);
angularAxis->setRange(angularMin, angularMax);
//最后加载到视图上
ChartView *chartView = new ChartView();
chartView->setChart(chart);
chartView->setRenderHint(QPainter::Antialiasing);
结构大概就是上面的那个结构,一般变化的就是数据表现形式:可以是线性QLineSeries、散点QScatterSeries,区域QAreaSeries等,或者两两结合的,比如线性跟区域的结合等;或者散点中的点的形状大小的变化。
2.2. 线面结合(区域填充)
线性QLineSeries跟区域QAreaSeries的结合,就是在一个区域内进行一个填充。区域是由QAreaSeries设置上方线条(setUpperSeries)和下方线条(setLowerSeries)构成的,可不设置下方线条,线条也可不闭环。代码如下:
QLineSeries* series = new QLineSeries(); // 创建一个散点绘图数据集对象
series->setPen(QPen(QColor(Qt::blue)));
for(int i=0;i<100;i++){
series->append(i/100.0*360.0,qSin(i/100.0*M_PI*6)*2);
}
QAreaSeries *series4 = new QAreaSeries();
series4->setUpperSeries(series);
series4->setPen(QPen(QColor(255,150,20,0)));
series4->setBrush(QColor(255,150,20,50));
....
chart->addSeries(series);
chart->addSeries(series4);
...
series->attachAxis(angularAxis);
series->attachAxis(radialAxis);
series4->attachAxis(angularAxis);
series4->attachAxis(radialAxis);
....
效果图如下:
2.3. QScatterSeries的点
这里着重说一下散点类QScatterSeries,它的点可改变大小和形状,大概有以下几种方式。
2.3.1. 只设置Mask形状和大小
散点类QScatterSeries可设置Marker的形状和大小,形状默认为圆(QScatterSeries::MarkerShapeCircle),这里设置的是长方形,它只有这两个形状,代码如下:
QScatterSeries *series2 = new QScatterSeries();
series2->setMarkerShape(QScatterSeries::MarkerShapeRectangle);
qreal markSize=7.0;
series2->setMarkerSize(markSize);
2.3.2. 加载图片填充点
QScatterSeries 可通过设置刷子来改变点Marker内的填充,可以看QBrush的构造函数,可用QImage进行初始化,所以我们可以直接加载图片作为点内部的填充,其中,要搭配Marker来控制点的大小和形状。
QImage star(":/res/ssStar.png");
star=star.scaled(markSize,markSize);
series2->setBrush(star);
series2->setPen(QColor(Qt::transparent));
2.3.3. QPainter绘制图案填充点
既然可以用QImage进行填充点,那么就可以用painter进行绘制。
QImage star(markSize, markSize, QImage::Format_ARGB32);
star.fill(Qt::transparent);
QPainter painter(&star);
painter.setRenderHint(QPainter::Antialiasing);
painter.setPen(QPen(Qt::blue));
painter.drawLine(QLineF(0,markSize/2.0, markSize,markSize/2.0));
painter.drawLine(QLineF(markSize/2.0, markSize, markSize, 0));
painter.drawLine(QLineF(0.15*markSize,0.15*markSize, 0.85*markSize,0.85*markSize));
painter.drawLine(QLineF(0.15*markSize, 0.85*markSize, 0.85*markSize, 0.15*markSize));
series2->setBrush(star);
series2->setPen(QColor(Qt::transparent));
效果图如下:
散点若与线条同路径,与上面的线面结合的在同一个坐标下,图如下,
3. 结束语
最近学了下QCustomPlot,发现QCustomPlot更简单,性能更好,而且只需要有两个线条就可以完成上图,下篇博客就写这个。综上所述,这个只是个示例,若用在项目中,还是准备用QCustomPlot。