本章節是仿造echarts的熱力圖:地址html
QCustomPlot中熱力圖叫QCPColorMap,因此應該稱爲顏色圖更爲合適一點,通常來講一副顏色圖會由兩個部分組成apache
除了這兩個,還有一個重要的傢伙,那就是顏色漸變QCPColorGradient,它決定了顏色圖的數據對應的是什麼顏色,QCPColorGradient預約義了9種顏色漸變,以下圖所示數組
顏色圖除了x、y兩個位置,還有一個z位置,z位置對應着顏色漸變中的顏色取值位置echarts
void MainWindow::setupHeatmapDemo(QCustomPlot *customPlot) { QVector<QString> hours = {"12a", "1a", "2a", "3a", "4a", "5a", "6a", "7a", "8a", "9a","10a","11a", "12p", "1p", "2p", "3p", "4p", "5p", "6p", "7p", "8p", "9p", "10p", "11p"}; QVector<QString> days = {"Saturday", "Friday", "Thursday", "Wednesday", "Tuesday", "Monday", "Sunday"}; QVector<QVector<double>> data = {{0,0,5},{0,1,1},{0,2,0},{0,3,0},{0,4,0},{0,5,0},{0,6,0},{0,7,0},{0,8,0},{0,9,0},{0,10,0},{0,11,2},{0,12,4},{0,13,1},{0,14,1},{0,15,3},{0,16,4},{0,17,6},{0,18,4}, {0,19,4},{0,20,3},{0,21,3},{0,22,2},{0,23,5},{1,0,7},{1,1,0},{1,2,0},{1,3,0},{1,4,0},{1,5,0},{1,6,0},{1,7,0},{1,8,0},{1,9,0},{1,10,5},{1,11,2},{1,12,2},{1,13,6},{1,14,9},{1,15,11}, {1,16,6},{1,17,7},{1,18,8},{1,19,12},{1,20,5},{1,21,5},{1,22,7},{1,23,2},{2,0,1},{2,1,1},{2,2,0},{2,3,0},{2,4,0},{2,5,0},{2,6,0},{2,7,0},{2,8,0},{2,9,0},{2,10,3},{2,11,2},{2,12,1}, {2,13,9},{2,14,8},{2,15,10},{2,16,6},{2,17,5},{2,18,5},{2,19,5},{2,20,7},{2,21,4},{2,22,2},{2,23,4},{3,0,7},{3,1,3},{3,2,0},{3,3,0},{3,4,0},{3,5,0},{3,6,0},{3,7,0},{3,8,1}, {3,9,0},{3,10,5},{3,11,4},{3,12,7},{3,13,14},{3,14,13},{3,15,12},{3,16,9},{3,17,5},{3,18,5},{3,19,10},{3,20,6},{3,21,4},{3,22,4},{3,23,1},{4,0,1},{4,1,3},{4,2,0},{4,3,0},{4,4,0}, {4,5,1},{4,6,0},{4,7,0},{4,8,0},{4,9,2},{4,10,4},{4,11,4},{4,12,2},{4,13,4},{4,14,4},{4,15,14},{4,16,12},{4,17,1},{4,18,8},{4,19,5},{4,20,3},{4,21,7},{4,22,3},{4,23,0},{5,0,2}, {5,1,1},{5,2,0},{5,3,3},{5,4,0},{5,5,0},{5,6,0},{5,7,0},{5,8,2},{5,9,0},{5,10,4},{5,11,1},{5,12,5},{5,13,10},{5,14,5},{5,15,7},{5,16,11},{5,17,6},{5,18,0},{5,19,5},{5,20,3},{5,21,4}, {5,22,2},{5,23,0},{6,0,1},{6,1,0},{6,2,0},{6,3,0},{6,4,0},{6,5,0},{6,6,0},{6,7,0},{6,8,0},{6,9,0},{6,10,1},{6,11,0},{6,12,2},{6,13,1},{6,14,3},{6,15,4},{6,16,0},{6,17,0},{6,18,0}, {6,19,0},{6,20,1},{6,21,2},{6,22,2},{6,23,6}}; QCPColorMap *heatmap = new QCPColorMap(customPlot->xAxis, customPlot->yAxis); // 構造一個顏色圖 heatmap->data()->setSize(hours.size(), days.size()); // 設置顏色圖數據維度,其內部維護着一個一維數組(通常表現爲二維數組),這裏能夠理解爲有多少個小方塊 heatmap->data()->setRange(QCPRange(0.5, hours.size() - 0.5), QCPRange(0.5, days.size() - 0.5)); // 顏色圖在x、y軸上的範圍 // 設置軸的顯示,這裏使用文字軸,若是這部分還不會的請看 QCustomPlot之個性化外觀(二)這章節 QSharedPointer<QCPAxisTickerText> xTicker(new QCPAxisTickerText); QSharedPointer<QCPAxisTickerText> yTicker(new QCPAxisTickerText); xTicker->setTicks(labelPositions(hours, 0.5), hours); yTicker->setTicks(labelPositions(days, 0.5), days); xTicker->setSubTickCount(1); yTicker->setSubTickCount(1); customPlot->xAxis->setTicker(xTicker); customPlot->yAxis->setTicker(yTicker); customPlot->xAxis->grid()->setPen(Qt::NoPen); customPlot->yAxis->grid()->setPen(Qt::NoPen); customPlot->xAxis->grid()->setSubGridVisible(true); customPlot->yAxis->grid()->setSubGridVisible(true); customPlot->xAxis->setSubTicks(true); customPlot->yAxis->setSubTicks(true); customPlot->xAxis->setTickLength(0); customPlot->yAxis->setTickLength(0); customPlot->xAxis->setSubTickLength(6); customPlot->yAxis->setSubTickLength(6); customPlot->xAxis->setRange(0, hours.size()); customPlot->yAxis->setRange(0, days.size()); for (int x = 0; x < hours.size(); ++x) { for (int y = 0; y < days.size(); ++y) { int z = data.at(hours.size() * y + x).at(2); if (z) heatmap->data()->setCell(x, y, z); // 若是z不爲0,則設置顏色值的位置 else heatmap->data()->setAlpha(x, y, 0); // z爲0,設置爲透明 } } QCPColorScale *colorScale = new QCPColorScale(customPlot); // 構造一個色條 colorScale->setType(QCPAxis::atBottom); // 水平顯示 customPlot->plotLayout()->addElement(1, 0, colorScale); // 在顏色圖下面顯示 heatmap->setColorScale(colorScale); QCPColorGradient gradient; // 色條使用的顏色漸變 gradient.setColorStopAt(0.0, QColor("#f6efa6")); // 設置色條開始時的顏色 gradient.setColorStopAt(1.0, QColor("#bf444c")); // 設置色條結束時的顏色 heatmap->setGradient(gradient); // colorMap->rescaleDataRange(); // 自動計算數據範圍,數據範圍決定了哪些數據值映射到QCPColorGradient的顏色漸變當中 heatmap->setDataRange(QCPRange(0, 10)); // 爲了保持與echart的例子一致,咱們這裏手動設置數據範圍 heatmap->setInterpolate(false); // 爲了顯示小方塊,咱們禁用插值 // 保持色條與軸矩形邊距一致 QCPMarginGroup *marginGroup = new QCPMarginGroup(customPlot); customPlot->axisRect()->setMarginGroup(QCP::msLeft | QCP::msRight, marginGroup); colorScale->setMarginGroup(QCP::msLeft | QCP::msRight, marginGroup); }
其中labelPositions
是返回labels所對應的位置的dom
QVector<double> labelPositions(const QVector<QString> &labels, double offset = 0) { QVector<double> result(labels.size()); for (int i = 0; i < labels.size(); ++i) result[i] = i + offset; return result; }
動態熱力圖其實就是從新設置z的值ui
void MainWindow::setupDynamicHeatmapDemo(QCustomPlot *customPlot) { setupHeatmapDemo(customPlot); connect(&dataTimer, SIGNAL(timeout()), this, SLOT(dynamicHeatmapSlot())); dataTimer.start(1000); } void MainWindow::dynamicHeatmapSlot() { auto *colorMap = static_cast<QCPColorMap *>(ui->customPlot->plottable(0)); int keySize = colorMap->data()->keySize(); int valueSize = colorMap->data()->valueSize(); for (int x = 0; x < keySize; ++x) { for (int y = 0; y < valueSize; ++y) { if (colorMap->data()->alpha(x, y)) // 當前不是透明的,就從新設置z的值 colorMap->data()->setCell(x, y, QRandomGenerator::global()->bounded(1, 15)); } } ui->customPlot->replot(); }