热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

Qt绘制热力图

0.前言热力图是一种重要的数据可视化方式,可以直观地展现空间数据的疏密程度或频率高低。本文将使用QPainter+QImage来实现热力图绘制,效果参照百度ECharts图表库:《
0.前言

热力图是一种重要的数据可视化方式,可以直观地展现空间数据的疏密程度或频率高低。本文将使用QPainter+QImage来实现热力图绘制,效果参照百度ECharts图表库:

《Qt绘制热力图》

《从前慢》 ——–木心

记得早先少年时

大家诚诚恳恳

说一句 是一句

清早上火车站

长街黑暗无行人

卖豆浆的小店冒着热气

从前的日色变得慢

车,马,邮件都慢

一生只够爱一个人

从前的锁也好看

钥匙精美有样子

你锁了 人家就懂了

目录

1.实现思路

2.实现细节

3.代码链接

4.参考

1.实现思路

主要步骤如下:

a.每个单独的点为径向渐变色的圆,且透明度从中心到边缘逐渐降低

QRadialGradient gradient(posX,posY,radius); //径向渐变
gradient.setColorAt(0,QColor(0,0,0,alpha)); //点的透明度
gradient.setColorAt(1,QColor(0,0,0,0));
painter.setBrush(gradient);
painter.drawEllipse(QPointF(posX,posY),radius,radius);

b.多个点组合时,透明度是互相叠加的,所以我们先用透明度绘制一个Image(透明度就表示热度)

//透明度用Format_Alpha8就行了
_dataImg=QImage(ImgWidth,ImgHeight,QImage::Format_Alpha8);
_dataImg.fill(Qt::transparent);
//接下来追加绘制圆点

c.如果一个点出现多次,那么就需要有权重的概念,可以根据重复最多的点来作为计算的标准,也可以根据重复次数分段

//权重统计表(把权重单独拿出来,就可以不用遍历数据点来计算了)
//加()初始化为0
int *_countTable=new int[ImgWidth*ImgHeight]();
//以最大次数来计算该点的权重
const uchar alpha=uchar(_countTable[posX+posY*ImgWidth]/(double)_maxCount*255);

d.透明度的图绘制完成后就可以填充颜色,颜色根据透明度从计算好的颜色表中查表获得

void MainWindow::drawHeatImg()
{
//把alpha值转为颜色值
for(int row=0;row<_dataImg.height();row++)
{
//dataimg QImage::Format_Alpha8,一个点1个字节
const uchar *line_data=_dataImg.scanLine(row);
//heatimg QImage::Format_ARGB32,一个点4个字节
QRgb *line_heat=reinterpret_cast(_heatImg.scanLine(row));
for(int col=0;col<_dataImg.width();col++)
{
//根据alpha透明度从颜色表取颜色
line_heat[col]=_colorList[line_data[col]];
}
}
}
2.实现细节

a.颜色表的实现

颜色表我使用的线性渐变会知道Image来取颜色的方式,因为单纯 QLinearGradient 好像没有取某个点颜色的接口;还有就是计算颜色透明度的时候可能要考虑热力图整体的透明度。

颜色表的元素类型为 QRgb ,是 uint32 的 typedef ,表示 #AARRGGBB。

//根据线性渐变色条得到颜色表
QLinearGradient linear=QLinearGradient(QPoint(0,0),QPoint(255,0));
linear.setColorAt(0, Qt::blue);
linear.setColorAt(0.4, Qt::blue);
linear.setColorAt(0.5, Qt::cyan);
linear.setColorAt(0.6, Qt::green);
linear.setColorAt(0.8, Qt::yellow);
linear.setColorAt(0.95, Qt::red); //255对应透明度最大值,即中心点
//把渐变色绘制到Img方便取颜色
QImage img(256,1,QImage::Format_ARGB32);
QPainter painter(&img);
painter.fillRect(img.rect(),linear);
//HeatAlpha为热力图整体透明度
quint32 alpha=0;
for(quint32 i=0;i<256;i++){
//根据热力图透明度来计算颜色表的透明度
alpha=HeatAlpha/255.0*i;
//typedef unsigned int QRgb: format #AARRGGBB
//颜色+透明度
_colorList[i]=img.pixel(i,0)&0x00FFFFFF|(alpha<<24);
}

b.点的追加

如果点不是重合的,那么直接在透明度图中追加绘制就行,如果点重合了,那么出于权重对透明度的影响,需要重新绘制透明度图。

//为什么不直接if(pos_count>_maxCount)才重新绘制?
//而是有两个点叠加if(pos_count>1)就重新绘制?
//因为单纯的叠加目前还没有带入权重来计算,如果最大权重更大,那么这个叠加的点颜色就走样了
if(pos_count>1){
if(pos_count>_maxCount)
_maxCount=pos_count;
drawDataImg();
}else{
drawDataPoint(pt);
}

c.透明度图转热力图

因为我们是先绘制的透明度图来表示热度,再通过透明度查表来填充的颜色,所以我们需要两个Image。

//data用alpha叠加
_dataImg=QImage(ImgWidth,ImgHeight,QImage::Format_Alpha8);
_dataImg.fill(Qt::transparent);
//热力图通过alpha值查表
_heatImg=QImage(ImgWidth,ImgHeight,QImage::Format_ARGB32);
_heatImg.fill(Qt::transparent);

 绘制热力图的时候,我们使用 QImage 的 scanLine() 函数,以及颜色查表来提高效率。

//把alpha值转为颜色值
for(int row=0;row<_dataImg.height();row++)
{
//dataimg QImage::Format_Alpha8,一个点1个字节
const uchar *line_data=_dataImg.scanLine(row);
//heatimg QImage::Format_ARGB32,一个点4个字节
QRgb *line_heat=reinterpret_cast(_heatImg.scanLine(row));
for(int col=0;col<_dataImg.width();col++)
{
//根据alpha透明度从颜色表取颜色
line_heat[col]=_colorList[line_data[col]];
}
}
3.代码链接

代码git链接:

https://github.com/gongjianbo/MyTestCode/tree/master/Qt/MyHeatMap

实现效果:

《Qt绘制热力图》

《Qt绘制热力图》

4.参考

JS版:https://blog.csdn.net/HiddlestonCloud/article/details/83743449

Qt版:https://blog.csdn.net/pbe_sedm/article/details/8982357


推荐阅读
  • 本文节选自《NLTK基础教程——用NLTK和Python库构建机器学习应用》一书的第1章第1.2节,作者Nitin Hardeniya。本文将带领读者快速了解Python的基础知识,为后续的机器学习应用打下坚实的基础。 ... [详细]
  • 【转】强大的矩阵奇异值分解(SVD)及其应用
    在工程实践中,经常要对大矩阵进行计算,除了使用分布式处理方法以外,就是通过理论方法,对矩阵降维。一下文章,我在 ... [详细]
  • 编写SharePoint的EventReceiver需要用到ListTemplateID来进行绑定,下面的列表对于编程和排查错误都是个很好的索引.Listtem ... [详细]
  • 本文介绍了 Python 中的基本数据类型,包括不可变数据类型(数字、字符串、元组)和可变数据类型(列表、字典、集合),并详细解释了每种数据类型的使用方法和常见操作。 ... [详细]
  • 本文介绍了如何使用Python爬取妙笔阁小说网仙侠系列中所有小说的信息,并将其保存为TXT和CSV格式。主要内容包括如何构造请求头以避免被网站封禁,以及如何利用XPath解析HTML并提取所需信息。 ... [详细]
  • MySQL初级篇——字符串、日期时间、流程控制函数的相关应用
    文章目录:1.字符串函数2.日期时间函数2.1获取日期时间2.2日期与时间戳的转换2.3获取年月日、时分秒、星期数、天数等函数2.4时间和秒钟的转换2. ... [详细]
  • Python 数据可视化实战指南
    本文详细介绍如何使用 Python 进行数据可视化,涵盖从环境搭建到具体实例的全过程。 ... [详细]
  • Redis 是一个高性能的开源键值存储系统,支持多种数据结构。本文将详细介绍 Redis 中的六种底层数据结构及其在对象系统中的应用,包括字符串对象、列表对象、哈希对象、集合对象和有序集合对象。通过12张图解,帮助读者全面理解 Redis 的数据结构和对象系统。 ... [详细]
  • 开发笔记:前端之前端初识
    开发笔记:前端之前端初识 ... [详细]
  • MySQL 5.7 服务端在 Windows 上的安装与配置
    本文详细介绍了在 Windows 系统上安装和配置 MySQL 5.7 服务端的方法,包括 my.ini 配置文件的设置、初始化数据库、启动服务以及设置用户权限等步骤。 ... [详细]
  • LeetCode 实战:寻找三数之和为零的组合
    给定一个包含 n 个整数的数组,判断该数组中是否存在三个元素 a、b、c,使得 a + b + c = 0。找出所有满足条件且不重复的三元组。 ... [详细]
  • vue引入echarts地图的四种方式
    一、vue中引入echart1、安装echarts:npminstallecharts--save2、在main.js文件中引入echarts实例:  Vue.prototype.$echartsecharts3、在需要用到echart图形的vue文件中引入:   importechartsfrom&amp;quot;echarts&amp;quot;;4、如果用到map(地图),还 ... [详细]
  • Linux 防火墙与端口管理必备命令
    在使用 Linux 系统进行服务部署和问题排查时,防火墙和端口管理是不可或缺的操作。本文将详细介绍如何查看防火墙状态、端口占用情况,以及如何开放和关闭端口,帮助初学者更好地掌握这些技能。 ... [详细]
  • 本文探讨了 TypeScript 中泛型的重要性和应用场景,通过多个实例详细解析了泛型如何提升代码的复用性和类型安全性。 ... [详细]
  • 面试题总结_2019年全网最热门的123个Java并发面试题总结
    面试题总结_2019年全网最热门的123个Java并发面试题总结 ... [详细]
author-avatar
red_小火柿子
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有