TW洞见 | 可视化你的足迹

今日洞见

文章作者来自ThoughtWorks:邱俊涛。

本文所有内容,包括文字、图片和音视频资料,版权均属ThoughtWorks公司所有,任何媒体、网站或个人未经本网协议授权不得转载、链接、转贴或以其他方式复制发布/发表。已经本网协议授权的媒体、网站,在使用时必须注明"内容来源:ThoughtWorks洞见",并指定原文链接,违者本网将依法追究责任。

可视化你的足迹

数据可视化可以让读者以一种轻松的方式来消费数据,人类大脑在处理图形的速度是处理文本的66,000倍,这也是人们常常说的一图胜千言。在本文中,我们通过将日常中很容易收集到的数据,通过一系列的处理,并最终展现在地图上。这仅仅是GIS的一个很简单场景,但是我们可以看到,当空间数据和地图结合在一起时,可以在可视化上得到很好的效果,读者可以很容易从中获取信息。

我们在本文中会制作一个这样的地图,图中灰色的线是城市中的道路,小六边形表示照片拍摄地。颜色表示当时当地拍摄照片的密度,红色表示密集,黄色为稀疏。可以看到,我的活动区域主要集中在左下角,那是公司所在地和我的住处,:)

要展现数据,首先需要采集数据,不过这些已经在日常生活中被不自觉的被记录下来了。

数据来源

如果你开启了iPhone相机中的定位功能,拍照的时候,iPhone会自动把当前的地理信息写入到图片的元数据中,这样我们就可以使用这些数据来做进一步的分析了。

我在去年学习OpenLayers的时候已经玩过一些简单的足迹可视化,另外还有一篇全球地震信息的可视化,但是仅仅是展示矢量信息,并没有深入,而且都是一些前端的JavaScript的代码。最近又在重新整理之前的GIS知识,重新把这个作为例子来练手。当然,这次会涉及一些地图编辑,空间计算的内容。

我的照片一般都通过Mac自带的Photos管理(前身iPhoto),手机里照片会定期同步上去。老版本的iPhoto用的是XML文件来存储照片的EXIF数据,新的Photos的实现里,数据被存储在了好几个SQLite数据库文件中,不过问题不大,我们只需要写一点Ruby代码就可以将数据转化为标准格式,这里使用GeoJSON,GeoJSON既可以方便人类阅读,也可以很方便的导入到PostGIS或者直接在客户端展现。

实现步骤

我们现在要绘制照片拍摄的密度图,大概需要这样一些步骤:

  1. 抽取照片的EXIF信息(经度,纬度,创建时间等)
  2. 编写脚本将抽取出来的信息转换成通用格式(GeoJSON)
  3. 使用QGIS将这些点的集合导入为图层
  4. 插入一些由六边形组成的图层(设置合适的大小)
  5. 计算落在各个多边形中的点的个数,并生成新的图层heatmap
  6. 使用MapServer来渲染基本地图

数据抽取

Mac上的Photos会将照片的元数据存储在一个SQLite3格式的数据库中,文件名为Library.apdb,通常位于这个位置~/Pictures/Photos\ Library.photoslibrary/Database/apdb/Library.apdb。这个文件可以通过SQLite3的客户端直接打开,不过由于可能有其他进程(Mac自己的)打开了该文件,所以会有锁文件,你可能需要先将这个文件拷贝到另外一个位置。

然后将表RKVersion中的部分信息导出即可,SQLite内置了很方便的导出功能,通过它提供的shell客户端sqlite3,将信息导出到csv文件中:

注意这里的日期,苹果的日期偏移和其他公司不同,始于2001年1月1日,所以要在imageDate之后加上这个base值,然后将文件以.csv的格式导出到places-ive-been.csv中,该文件包含3列:时间,纬度,精度。

转换为GeoJSON

方便以后的转换起见,我们将这个文件转换成GeoJSON(其实很多客户端工具可以支持CSV的导入,不过GeoJSON更为标准一些)。

这段脚本可以将我们的.csv转换成标准的geojson格式,注意此处的空间投影使用的是EPSG:4326。

导入为QGIS图层

QGIS是一个开源的GIS套件,包括桌面端的编辑器和服务器端,这里我们只是用器桌面端来进行图层的编辑。

将我们的GeoJSON导入之后,会看到这样的一个可视化的效果!

我们还可以导入其他的地图图层,这样可以清楚的看到点所在的区域(国家地图图层可以在此处下载):

好了,有了基础数据之后,我们来作进一步的数据分析 – 即生成密度图。首先使用QGIS的插件MMQGIS的生成多边形图层功能(Create -> Create Grid Layer),为了处理速度,我们可以将地图放大到一定范围(我选择西安市,我在这里活动比较密集)。

选择六边形hexagon,并设置合适的大小(如果是3857参考系,即按照公里数来设置,会比较容易一些,如果是4326,则需要自己计算)。简而言之,需要保证每个格子都包含一些点,不至于太密,也不至于太稀疏。

计算密度

QGIS提供了很多的数据分析功能,我们在这个例子中使用(Vector -> Analysis Tools -> Points in Polygon)工具,这个工具需要两个图层,一个是点集图层,一个是多边形图层。然后会将结果生成到一个新的图层中,我们可以将其命名为places-ive-been-density.shp,同时需要指定一个字段来存储统计出来的值(density)。

这个过程可能会花费一点时间,根据需要计算的点集合多边形的格式(也就是地图上的区域)。

完成之后会得到一个Shapefile(其实是一组,具体可以参看这里)。其实在这个过程中,绝大多数多边形是不包含任何数据的,我们需要过滤掉这些多余的多边形,这样可以缩减绘制地图的时间。

我们可以将这个文件导入到PostGIS中进行简化:

这里的shp2pgsql命令是GDAL工具包提供的命令,用以将Shapefile导入到PostGIS中,你可以通过

来安装。

GDAL会提供很多的工具,比如用来转换各种数据格式,投影,查看信息等等。

导入之后,我们可以在PostGIS的客户端查看,编辑这些数据等。比如在过滤之前,

我们导入的数据中有103166条记录:

而过滤之后,我们仅剩下749条数据。

通过GDAL提供的另一个工具ogr2ogr可以方便的执行过滤,并生成新的Shapefile:

这条命令可以得到一个新的文件,这个就是最终的用来绘制地图的文件了。

绘制地图

开源世界中有很多的工具可以完成地图的绘制,比如MapServer,GeoServer,Mapnik等等。我们在这篇文章中使用MapServer来完成地图的绘制,MapServer的安装和配置虽然比较容易,但是也需要花费一些时间,所以我将其放到了这个repo中,你可以直接clone下来使用。(需要你在虚拟机中安装ansible来完成provision)。

MapServer的配置很简单,类似于一个XML,不过是自定义的格式:

这些配置基本上都比较自解释,比如设置图片格式,图片大小,Shapefile的路径,图层的名称等,MapServer的文档在开源软件中来说,都算比较烂的,但是对于这些基本概念的解释还比较详尽,大家可以去这里参考。

这里我们定义了一个图层,每个Map中可以定义多个图层(我们完成的最终效果图就是西安市的道路图和照片拍摄密度图两个图层的叠加)。

这个配置绘制出来的地图是没有颜色差异的,全部都是255 255 178。不过MapServer的配置提供了很好的样式定义,比如我们可以定义这样的一些规则:

  1. 如果密度为1,则设置颜色为淡黄
  2. 如果密度在1-2,则设置为比淡黄红一点的颜色
  3. 以此类推

这样我们的地图展现出来就会比较有层次感,而且通过颜色的加深,也能体现热图本身的含义。

同样的原理,如果将那些自己创建的多边形替换为行政区域划分的多边形,则可以得到另外一种形式的热图:

总结

我们通过使用一些开源工具(MapServer,QGis,PostGIS,GDAL等),构建出一个基于GIS的数据可视化框架。在这个stack上,我们可以很容易的将一些其他数据也通过可视化的方式展现出来(公用自行车站点分布,出租车分布等等)。MapServer可以发布标准的WMS服务,因此可以很好的和客户端框架集成,从而带来更加友好的用户体验。

原文发布于微信公众号 - 思特沃克(ThoughtWorks)

原文发表时间:2015-09-22

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏企鹅号快讯

抓取百度指数引发的图像数字识别

作者介绍: 叶成,数据分析师,就职于易居中国,热爱数据分析和挖掘工作,擅长使用Python倒腾数据。 前言 学习爬虫也有段时间了,闲着无趣,想找点项目练练手,于...

4666
来自专栏前端说吧

Echarts - 树图实现四个层级

我相信很多人和我一样,制作echats图标时,都会先去demo官网找相同的或者近似的效果,然后再此基础上改进成我们想要的那个。

2712
来自专栏地方网络工作室的专栏

解决因为手机设置字体大小导致h5页面在webview中变形的BUG

解决因为手机设置字体大小导致h5页面在webview中变形的BUG 首先,我们做了一个H5页面,在各种手机浏览器中打开都没问题。我们采用了rem单位进行布局,通...

7125
来自专栏哲学驱动设计

Rafy 领域实体框架 - 领域模型设计器(建模工具)设计方案

去年4月,我们为 Rafy 框架添加了领域模型设计器组件。时隔一年,谨以本文,简要说明该领域模型设计器的设计思想。 设计目标 Rafy 实体框架中以领域驱动设计...

30410
来自专栏日常学python

用Python来跳Michael Jackson的太空漫步

最近看到一个有意思的程序:ffmpeg。它是一套可以用来记录、转换数字音频、视频,并能将其转化为流的开源计算机程序。可以用来把视频转化为图片,在用 PIL 库把...

952
来自专栏JackieZheng

自己动手写可视化软件(代码已开源)

  一年多前,那时候我还在实习,正好上一个项目接近的尾声,紧随而来的就是一个大数据一体化的项目,包括了数据的采集、处理、计算、整合以及数据展示等。   而可视化...

2429
来自专栏菩提树下的杨过

Flash/Flex学习笔记(12):FMS 3.5之如何做视频实时直播

硬件条件:一个摄像头 + 一台FMS服务器即可 原理:摄像头实时采集视频源,然后推送到FMS服务器,其它客户从FMS上获取视频流。 需要做二个fla,一个用于向...

1898
来自专栏Python攻城狮

利用简书首页文章标题数据生成词云1.词云图2.推荐几个不错的词云图工具3.爬取数据,制作词云图

词云图,也叫文字云,是对文本中出现频率较高的“关键词”予以视觉化的展现,词云图过滤掉大量的低频低质的文本信息,使得浏览者只要一眼扫过文本就可领略文本的主旨。

3282
来自专栏FreeBuf

看我如何基于Python;Facepp打造智能监控系统

由于种种原因,最近想亲自做一个基于python&facepp打造的智能监控系统。 0x00:萌芽 1:暑假在家很无聊 想出去玩,找不到人。玩个lol(已卸载),...

5445
来自专栏贾老师の博客

游戏中的网络同步

2834

扫码关注云+社区

领取腾讯云代金券