前言
永安的自行车是固定车桩的,借车和换车都要去这样的车桩刷卡或者扫描才可以。
遥想当年刚来高教区的时候,和小伙伴三个人一起跑了很多地方去办卡,不仅要200押金,还要居住证等一大堆手续才能享受公共自行车的服务。直到今年春天,苏州市陆陆续续开始支持支付宝二维码借车,通过蚂蚁信用积分就能轻松借车,各类共享自行车也如雨后春笋般涌现。
前几天睡觉之前突发奇想,尝试把某个接口中的查询半径增加到了几百公里,然后顺利的返回了整个苏州市的永安自行车车桩数据。一鼓作气,一直折腾到两三点,让它自己一分钟抓取一次车桩的状态。看看整个苏州每个租车站点的使用情况是什么样。
数据采集
首先给数据库设计了两个表,一个记录永安各个站点的信息,另一个记录采集的时间和各个站点的使用情况(还有多少车能借)。
后端程序无非是数据抓取入库,非常简单,就不上代码了,呵呵。
为了能全自动的执行数据采集任务,一般在Windows环境下配置定时任务,Linux 服务器配置 crontab。
开始以一分钟一次的速度从半夜两点开始抓取。就这样一觉睡到第二天中午,猛然发现数据量已经增长的非常庞大,超过了一百万条。因为整个苏州有两千多个站点,每分钟都拍一次快照的话,数据量会增长的非常快。为了防止服务器爆炸,当晚十点多把定时任务关了。最终得到大约150MB的数据。
可视化 尝试1
这还不简单,直接把数据上传到 Carto 然后生成可视化文件不就行了?
但事实没那么简单。为了输出Carto支持的CSV格式,我得把上百万的数据逐一查一遍相应的站点信息(GPS坐标、名称什么的),使用了这个号称最好用的csv处理轮子 league/csv, 把执行内存调到了2G,等了二十分钟终于输出了一个庞大的CSV文件。数据中间用的是 GCJ-02 坐标,输出的时候我得把它转成 WGS-84,早知道我就应该当时入库的时候转换一下啊,唉。坐标转换用的是 EvilTransform。
Mysql 转换输出
费了半天劲才上传上去,选择动画效果,把每个参数都调了一个遍,数据可以按照时间变化,但没法由特定的值显示不同的样式。其他的一些显示方式支持根据某些字段,显示不同的样式,但由不支持时间序列。操作卡顿,渲染卡顿,效果实现不了,坑爹!放弃!
然后尝试了 Ploy.ly 平台,发现上传文件大小就直接限制了。
可视化 尝试2
既然平台不行,只能自己选框架慢慢开发了。
关于地图的基础框架,依然选用了鲁棒性很强的(Leaflet.js)。
由于是时间轴+各种数据的变化,时间控件选择了 Leaflet.timeline。
当然还有一些其他的插件可以选择,不过没空一个一个尝试了,例如:
关于底图数据,需要特别说一句。现在Leaflet的底图一般都是切片图片,然后今天偶然看到一个十分惊艳的基于WebGL的地图,当然矢量数据主要是Openstreetmap,不过不论是2D还是3D效果都非常好,可定制性也很强。下一步计划折腾一下这个底图插件。上一个Demo看一下: https://tangrams.github.io/simple-demo/
数据的采集时间是2017-05-12日 02:00 到 22:00,为了减少数据量首先我们得确定一个区域。这个区域选的是独墅湖高教区,因为附近情况比较熟悉,可以脑补各个车桩的画面。
独墅湖高教区的 Boundary Box 坐标: [120.71365356445312,31.248617076299006, 120.75485229492188,31.28383230543126]。 也就是说,坐标落到这个正方形里面,就是独墅湖高教区里面的车桩。这里转不转坐标其实影响不是很大,毕竟偏移量比较小。
经过此轮处理,车桩数量从两千多个减少到40多个。
所以我们该怎么构造SQL查询呢?
注:下面的园区 id SET是上一步根据 bbox 查出来的。
GeoJson 是一种针对地理信息的通用Json格式,可以描述各种基于地理坐标的点、线、面,更多信息参阅官网手册。而我们这个可视化程序主要是读取自行车的GeoJson文件,然后再根据时间显示出来。
经过后来测试,数据量还是太大,所以后端每隔10分钟输出一次 GeoJson 数据,json文件也降到了不到 2MB:
好了,最后写前端代码,完成这个大作:
最终显示效果
从下图可以看出从早上6点一直到晚上10点的自行车规律,早中晚三个时段借车还车都很频繁。
但是貌似晚上9点以后,大量车桩都没车了,小伙伴猜测可能是被永安公司调度走了…
另外推荐一个GIF截图工具 ScreenToGif, 整个软件只有一个文件,打开即用,解决了我一大难题。