浅谈heatmap

小小猫钓小小鱼 小小猫钓小小鱼     2022-09-18     402

关键词:

在自然界之中,蛇的眼睛有夜视功能,即便是茫茫黑夜,它也能轻而易举的找到猎物,这是因为任何物体都会辐射热红外,且辐射的高低和温度成正比,由于生命体的体温会明显高于周围环境的温度,所以在蛇眼面前便无处遁形。热红外成像被广泛应用于军事领域,士兵带上能识别热红外的眼镜后能轻而易举的发现藏匿的敌人。

 

技术分享

热红外成像

唠叨了半天,听上去似乎有点跑题了,其实不然,对互联网从业者而言,同样需要有火眼金睛,以便识别网友的喜好,此时的衡量标准是点击,点击越多则表示越喜欢,此技术被称作Heatmap,已经有网站提供此类服务,如:clickdensityclicktalecrazyegg等等,甚至还有类似clickheat项目提供源代码供你直接使用。

不过最灵活的方案莫过于自己搞定,下面大概说说Heatmap的实现:

捕捉点击

当然,这需要Javascript来实现。为了不陷入浏览器兼容的泥潭,我们选择JQuery:

<script>

jQuery(document).ready(function() {
    $(document).mousedown(function(e) {
        if (e.clientX >= $(window).width() || e.clientY >= $(window).height()) {
            return;
        }

        $.get("/path/to/a/empty/html/file", {
            page_x       : e.pageX,
            page_y       : e.pageY,
            screen_width : screen.width,
            screen_height: screen.height
        });
    });
});

</script>

客户端使用Ajax通过GET方法触发一个空HTML页面,当然,还可以更简单点:

<script>

var image = new Image();
image.src = "...";

</script>

之所以要记录屏幕分辨率是因为有的情况下需要修正点击坐标。比如说,一个居中显示的定宽的页面,其同一个位置在不同分辨率下的坐标是不同的,当渲染图片的时候,坐标需要以一个分辨率为准进行修正。

另外,如果用户正在拖动滚动条,是不应该记录的。

分析日志

客户端使用Ajax通过GET方法触发一个空HTML页面,如此就会在服务端留下日志:

page_x=...&page_y=...&screen_width=...&screen_height=...

不同的日志格式,结果会有所不同,这里仅仅以此为例来说明问题,本文采用AWK来解析日志,当然你也可以使用Perl或别的你熟悉的语言:

#!/usr/bin/awk -f

BEGIN {
    FS="&";
}

NF == 4 {
    param["page_x"]        = "0";
    param["page_y"]        = "0";
    param["screen_width"]  = "0";
    param["screen_height"] = "0";

    split($0, query, "&");

    for (key in query) {
        split(query[key], item, "=");
        if (item[1] in param) {
                param[item[1]] = item[2];
        }
    }

    print "page_x:"       , param["page_x"];
    print "page_y:"       , param["page_y"];
    print "screen_width:" , param["screen_width"];
    print "screen_height:", param["screen_height"];

    print "
";
}

至于数据的持久化,是使用MongoDB或者别的,自己定夺,这里就不多说了。

渲染图片

出于演示方便的考虑,我使用了一些随机生成的数据,以Imagick为例,代码如下:

<?php

$coordinates = array();

for ($i = 0; $i < 1000; $i++) {
    $coordinates[] = array(rand($i, 1000), rand($i, 1000));
}

$max_repeat = max(
    array_count_values(
        array_map(function($v) { return "{$v[0]}x{$v[1]}"; }, $coordinates)
    )
);

$opacity = 1 - 1 / $max_repeat;

$heatmap_image = new Imagick();

$heatmap_image->newImage(1000, 1000, new ImagickPixel(‘white‘));
$heatmap_image->setImageFormat(‘png‘);

$plot_image = new Imagick(‘plot.png‘);

$iterator = $plot_image->getPixelIterator();
foreach($iterator as $row) {
    foreach ($row as $pixel) {
        $colors = $pixel->getColor();
        foreach (array(‘r‘, ‘g‘, ‘b‘) as $channel) {
            $color = $colors[$channel];
            if ($color !== 255) {
                $colors[$channel] = $color + ((255 - $color) * $opacity);
            }
        }

        $pixel->setColor("rgb({$colors[‘r‘]},{$colors[‘g‘]},{$colors[‘b‘]})");
    }

    $iterator->syncIterator();
}

$plot_size = $plot_image->getImageGeometry();

foreach ($coordinates as $pair) {
    $heatmap_image->compositeImage(
        $plot_image,
        Imagick::COMPOSITE_MULTIPLY,
        $pair[0] - $plot_size[‘width‘] / 2,
        $pair[1] - $plot_size[‘height‘] / 2
    );
}

$color_image = new Imagick(‘clut.png‘);

$heatmap_image->clutImage($color_image);

$heatmap_image->writeImage(‘heatmap.png‘);

?>

代码虽然很多,但并不复杂,其中用到了两个图片,分别是:plot.pngclut.png。实际应用时,有时候点击量会非常大,此时没有必要把所有的点击都渲染出来,而应该采取随机取样的策略,如果采用MongoDB持久化的话,可以参考:The Random Attribute

备注:代码参考image-tempest

最终展示

形象一点来说,其实就是通过CSS+Javascript把生成的图片盖在网页上,并调节图片透明度来达到合二为一的效果,篇幅所限,具体代码留给大家自己实现,例子效果可参考下图:

技术分享

Heatmap

BTW:热点可能会随着时间改变,为了能对照某个时间的网页,可以使用CutyCapt截屏。顺手再贴一个相关的项目:smt2(simple mouse tracking)。

有关Heatmap的详细介绍,还可以参考

收工!Heatmap虽然不是很复杂的技术,但涉及的方面却很繁杂,希望本文能帮到大家。

heatmap.js(代码片段)

...js也可以不用define(function(require,exports,module)require(‘./gmaps-heatmap.js/index.js‘);//这个作用不明,不引用应该也可以require(‘./heatmap.js‘);require(‘./heatmap.min.js‘);//引用不压缩版的就是正常的,压缩版的就不行,蛋疼varcommpent= 查看详情

面临 seaborn.heatmap() 的问题 [重复]

】面临seaborn.heatmap()的问题[重复]【英文标题】:Facingissuewithseaborn.heatmap()[duplicate]【发布时间】:2020-08-0205:11:47【问题描述】:我正在使用JupyterLab。当我从事数据可视化工作时,我遇到了seaborn.heatmap()的问题。单元格不均匀,图... 查看详情

在 heatmap.2 函数中更改标题字体大小?

】在heatmap.2函数中更改标题字体大小?【英文标题】:Changetitlefontsizeinheatmap.2function?【发布时间】:2013-12-2620:49:38【问题描述】:我正在使用heatmap.2包制作热图:heatmap.2(as.matrix(FOOBAR.txt[rowSums(abs(FOOBAR.txt))!=0,]),col=scaleyellowred,margin... 查看详情

heatmap.jsv2.0–最强大的web动态热图

Heatmap是用来呈现一定区域内的统计度量,最常见的网站访问热力图就是以特殊高亮的形式显示访客热衷的页面区域和访客所在的地理区域的图示。Heatmap.js这个 JavaScript 库可以实现各种动态热力图的网页,帮助您研究和可... 查看详情

heatmap热度图(代码片段)

#!/usr/bin/envpython#-*-coding:utf-8-*-importnumpyasnpimportpandasaspdimportseabornassnsfromscipyimportstatsimportmatplotlibasmplimportmatplotlib.pyplotasplt#热度图heatmapnp.random.seed(0)sns.set()unifor 查看详情

如何更改 R 中的 heatmap.2 颜色范围?

】如何更改R中的heatmap.2颜色范围?【英文标题】:Howtochangeheatmap.2colorrangeinR?【发布时间】:2013-07-2302:38:57【问题描述】:我正在使用gplot生成一个热图,显示治疗组与配对对照组的log2倍变化。使用以下代码:heatmap.2(as.matrix(SeqCo... 查看详情

r使用热力图(heatmap)可视化数据集(代码片段)

R使用热力图(heatmap)可视化数据集R使用热力图(heatmap)可视化数据集#安装、加载包install.packages(\'RNHANES\')library(RNHANES)library(tidyverse)******************************************************************************Warningmes 查看详情

将因子映射到 heatmap.2 中的颜色

】将因子映射到heatmap.2中的颜色【英文标题】:Mappingfactorstocolorsinheatmap.2【发布时间】:2013-08-0211:12:28【问题描述】:您好,我正在使用heatmap.2在R中制作热图。我想使用RowSideColors选项。但是,我不知道如何轻松地为行创建颜色... 查看详情

如何为 Seaborn Heatmap 彩条添加标签?

】如何为SeabornHeatmap彩条添加标签?【英文标题】:HowtoaddalabeltoSeabornHeatmapcolorbar?【发布时间】:2017-06-2420:05:20【问题描述】:如果我有以下数据和Seaborn热图:importpandasaspddata=pd.DataFrame(\'x\':(1,2,3,4),\'y\':(1,2,3,4),\'z\':(14,15,23,2))sns.h... 查看详情

r可视化使用ggplot2创建样本数据热力图(heatmap)

R可视化使用ggplot2创建样本数据热力图(heatmap)目录R可视化使用ggplot2创建样本数据热力图(heatmap)数据加载及变形 查看详情

使用传单函数 add_heatmap() 或 addHeatmap() 在 R 上创建热图

】使用传单函数add_heatmap()或addHeatmap()在R上创建热图【英文标题】:CreatingaheatmaponRusingleafletfunctionadd_heatmap()oraddHeatmap()【发布时间】:2021-08-0419:30:44【问题描述】:我正在尝试使用plotlyadd_heatmap()函数创建带有热图的绘图,但它会... 查看详情

如何在 heatmap.2 中展开树状图

】如何在heatmap.2中展开树状图【英文标题】:Howtoexpandthedendograminheatmap.2【发布时间】:2014-03-2520:15:34【问题描述】:我有以下带有树状图的热图。完整数据为here。问题是左边的树状图被压扁了。如何在不改变热图列大小的情况... 查看详情

如何使用 heatmap.js 保存由 canvas 标签生成的图像文件?

】如何使用heatmap.js保存由canvas标签生成的图像文件?【英文标题】:HowIcansavetheimagefilegeneratedbycanvastagwithheatmap.js?【发布时间】:2012-08-1802:14:02【问题描述】:如何将生成的画布heatmap.js保存为图像?我一直在用toDataURL()进行测试... 查看详情

Plotly Heatmap - 给出你的标题/索引名称

】PlotlyHeatmap-给出你的标题/索引名称【英文标题】:PlotlyHeatmap-Givingyourheader/indexnames【发布时间】:2021-12-0200:23:59【问题描述】:按照教程-https://plotly.com/python/heatmaps/如果你这样做importplotly.expressaspxdf=px.data.medals_wide(indexed=True)您... 查看详情

heatmap.js参数说明

blur:每个点都是两个圆组成的,分别为内圆和外圆;外圆越大,看起来这个点越模糊,内圆部分比较清晰;外圆的颜色比较固定且与内圆颜色不同,内圆的颜色由value确定;blur决定外圆与内圆的占比大小,值为0-1;值越大,外... 查看详情

如何为heatmap.js添加点击事件

...染。h337.create()创建对象,使用containter:指定容器,生成heatmapformat数据data,使用setData()函数设置数据。实例一:代码:<!DOCTYPEhtml><html><head><metacharset="UTF-8"><title></title><style>divwidth:600px;hei... 查看详情

sns.heatmap y 轴未被覆盖

】sns.heatmapy轴未被覆盖【英文标题】:sns.heatmapyaxisnotbeingoverwritten【发布时间】:2021-12-1803:51:49【问题描述】:目标:我想从具有2个索引的数据框创建热图。第二个索引,称为“Profile_Name”,也用于循环遍历数据框以创建多个热... 查看详情

r数据可视化5:热图heatmap

...相关性。1)需要什么格式的数据有很多的软件都可以做heatmap。我们要介绍的当然是R,R默认中提供了heatmap函数。当然,R中也有很多具有heatmap功能的包,比如ggplot2,gplots。今天我们介绍含有heatmap.2功能的gplots包。heatmap.2函数和我... 查看详情