上一篇和大家分享了《可视化之Berkeley Earth》,这次看一看下面这个网站---aqicn.org。先做一个提示:文末有惊喜~
该网站在中国有一定的权威性,PM2.5数据有一点敏感,它竟能提供全球级别,实时的,详尽的AQI数据,以及每个站点的经纬度(精度在十米内),它的口号“provide information as clean as the air one wish to have”——提供的每一份数据,如同每个人所期望的空气那样干净。
但该网站又有一点神秘感,没有过多的自我介绍,服务器IP来自美国,团队成员主要在北京,能够获取全球这么详细的数据,总感觉背后有很多不能说的秘密,网上只找到一篇《MY FAVORITE POLLUTION WEBSITE: AQICN.ORG》,感兴趣的可以读一下。
去年底抓取它的PM25实时数据,但觉得这是老外的良心网站,如果把URL和网站名称曝光,有被墙的隐患,所以没有透露。最近发现它竟然推出了json api的服务,生意越做越大,那今天老夫就“好事做到底”,揭底该网站四个未公开的,却是最重量级的服务。
1AQI Map
这是bounds查询的url:
https://api.waqi.info/mapq/bounds/?bounds={RECTANGLE}&inc=placeholders&k={KEY}&_={DATE}
官网API里仅开发了经纬度的点查询,但它自己使用是bounds面查询,另一个比较坑的是DATE参数,我自己验证是无效的,所以该API无法做到对历史数据的查询,当然,这也可以理解,毕竟每个站点数据更新时间不一,比如中亚可能好几个月才更新一次。因为之前的PM文章详细介绍过这部分,不再重复。
2AQI Forecast
如上是城市的天气预报服务,对应的数据url如下:
其中@参数是City编码,比如北京对应的id是1451。返回JSON对象如下:
不难理解,简单说一下框选的内容,city是该城市的内容,nearest是该城市范围内的气象站点,都有geo属性,提供对应的经纬度,误差在百米内。Iaqi留到下面说,先说相对简单的—forecast属性。顾名思义,也就是气象预报的内容,包括aqi和wind两部分。
先看上图对应表格中的AQI数值,每一项对应该时间点AQI的最大最小值。再看下图wind属性:
这个就不那么直观了,大家能看出对应关系吗?我看了一个多小时,没看出来,只好调试源码:三小时(采用UTC时间)为一时间段,对应三组数据,如上图,c是气温,获取气温的最大值和最小值,w[0],w[1]对应当前时段风速的最小最大值,w[2]是以正南为起始点,顺时针方向的旋转角度,表示风向,蓝色是风速的柱状图效果。这样看上去就很明白了吧。事后让同事看对应关系,他竟然很快就“蒙“对了。
3AQI Current
实时天气数据和forecast都在一个json对象中,对应iaqi属性,如下图所示,正好有11项,分别对应PM25,PM10等十一个指标。
对应的PM25属性如下:
p标志该指标名称为pm2.5,v中保存的是最近48小时内的极值和当前值,i是该数据的提供方。iaqi[0].h[2]下面的一堆乱码是什么,猜测应该是每个小时的PM25数值,用于显示左侧柱状图,可肉眼看不出其中的数值映射关系,这时候就需要用心眼了---调试,原来Decode代码如下:
我很好奇这段代码的出处,因为之前看高德地图中矢量瓦片中也采用了类似的解密方式,有了解的请告诉我,再次感谢。最终该函数将乱码decode为48个PM值。
4Forecast Map
当你在网页上看到该动态图时,假设你要实现这个效果,所需要的数据格式,用Canvas 2D还是WebGL,以及流畅度和交互式操作?
首先,每一个城市有自己的配置文件,应该是JSP动态网页来获取的,比如New York的配置信息如下:
如上请求的是pm25数据,model是ncep-aqm。根据这些参数,我们能够获取如下的url
https://forecast.waqi.info/forecast/aqi/ncep-aqm/best/pm25/conf.json
其对应的json信息如下:
如上也比较容易理解,其中size指该区域的像素宽高,bounds为经纬度范围,其中在usepa字段下有8.png(图片)和jsmap(二进制)这两种形式,可以简单的认为是PM25的范围分段。两者思路相同,网站使用的是jsmap这种形式。
如上,从lut可知pm25值分为17份,范围是0~500。将lut的17个区间归类到domain中,domain[i]对应range[i]份。无论是jsmap还是png,规范都一致(png更精细一些)。不同的是files,png对应的是图片的相对路径,效果如下。而jsmap是二进制流形式
代码中会给出一个色带"#ffffff", "#5ec569", "#b2d744","#f2c500", "#fe8d00", "#fa0067"],等分为17份,形成渐变色,然后根据jsmap对应的lut构造出一个level-color的分段映射表。保存在this.stream.colors.lut属性中。
创建好了颜色表,接着就会请求对应时段的数据,url如下:
https://forecast.waqi.info/forecast/aqi/ncep-aqm/best/pm25/jsmap/stream.jsmap
对该数据进行解码后参与canvas的渲染,解码的算法和上面的decode相似,最终会解析为一个点串points,里面有v,x,y,n四个分量,分别是pm25值对应颜色表中的value值,xy是对应该区域的像素偏移量,n标识该值连续的次数。这样,建立了最终的value-level-color的完整映射关系,通过canvas 2d完整动态渲染的整个过程。
5其他
在技术角度,把AQICN分解的差不多了,不知道大家有什么收获,因为篇幅太长,所以本篇就到此结束吧。如果有不对的地方或疑问,不妨留言交流。
下一篇会介绍earth.nullschool这个可视化效果很棒的网站,然后会再来一篇个人对这三个网站的对比和分析,把一些个人的想法拿出来和大家分享。
今天就写到这,在公众号中回复“AQICN”,不区分大小写,可以获取本文的Demo。