初始化创建画布

我目前正在为Three.js编写下一本书,其中一章涉及可视化开放数据。 在寻找可以使用的数据时,我遇到了来自NOAA的一组数据。 通过此站点,您可以以网格格式下载一组全世界的每月降水报告。 因此,我下载了它们,然后开始处理数据以查看其外观和使用方式。 在本文中,我不会向您展示基于Three.js的结果,但是我将为您提供一个快速概述,如何获得最初用于调试目的的格式:

在此图像中,您可以看到2012年7月全球对月降水量的对数。我还创建了一个简单的站点来显示此动画以及正在运行的动画。

因此,您需要做什么才能将可以从NOAA站点下载的集转换为可视的内容。

  • 下载并转换NetCDF格式。
  • 加载生成的CSV文件
  • 将CSV数据处理到世界网格中
  • 动画化两个月之间的过渡
  • 作为奖励:还可以创建图例以显示什么颜色表示什么

但是,首先,我们需要获取数据。

下载并转换NetCDF格式

我们需要做的第一件事就是获取数据。 我使用了以下链接:您可以在其中定义要下载的数据范围。 在此示例中,我使用了2012年1月至2012年12月的范围,并选择了创建子集而不绘制图的选项。

但是,下载它的格式不能直接用作我们基于HTML5画布的可视化的输入。 您可以使用ncdump-json创建一个JSON文件,但是仍然需要能够解释它,因此我选择了另一种方法。 我刚刚编写了一个简单的Java程序,将NetCDF格式转换为简单的CSV文件。

我使用了以下Maven依赖项:

<dependencies><dependency><groupId>edu.ucar</groupId><artifactId>netcdf</artifactId><version>4.2.20</version></dependency><dependency><groupId>commons-io</groupId><artifactId>commons-io</artifactId><version>2.4</version></dependency></dependencies>

并使用以下一段Java代码:

public class NetCDFDump {public static void main(String[] args) throws IOException, InvalidRangeException {String year = "2012";NetcdfFile nc = NetcdfFile.open("src/main/resources/X84.31.143.145.44.1.47.49.nc");Variable precip = nc.findVariable("precip");// use the shapes to create an arrayint[] shapes = precip.getShape();// month, lat, lonfloat[][][] data = new float[shapes[0]][shapes[1]][shapes[2]];// iterate over 12 (or 11) monthsint[] pos = new int[3];int[] shape = {1,1,1};for (int i = 0 ; i < shapes[0] ; i++) {pos[0]=i;for (int lat = 0 ; lat < shapes[1]; lat++) {pos[1] = lat;for (int lon = 0 ; lon < shapes[2]; lon++) {pos[2] = lon;Array result = precip.read(pos, shape);data[pos[0]][pos[1]][pos[2]] = result.getFloat(0);}}}// output data like this// month, lat, lon, humidityfloat[][] combined = new float[data[0].length][data[0][0].length];for (int m = 0 ; m < data.length ; m++) {File outputM = new File(year + "-out-" + m + ".csv");for (int lat = 0 ; lat < data[m].length ; lat++) {for (int lon = 0 ; lon < data[m][lat].length; lon++) {float value = data[m][lat][lon];if (value > -1000) {combined[lat][lon]+=value;} else {combined[lat][lon]+=-1000;}// write the string for outputfileStringBuffer bOut = new StringBuffer();bOut.append(m);bOut.append(',');bOut.append(lat);bOut.append(',');bOut.append(lon);bOut.append(',');bOut.append(value);bOut.append('\n');// write to month fileFileUtils.write(outputM,bOut,true);}}}// now process the combinedFile outputM = new File(year + "-gem.csv");for (int i = 0; i < combined.length; i++) {for (int j = 0; j < combined[0].length; j++) {StringBuffer bOut = new StringBuffer();bOut.append(i);bOut.append(',');bOut.append(j);bOut.append(',');bOut.append(combined[i][j]/data.length);bOut.append('\n');FileUtils.write(outputM, bOut, true);}}}
}

我不会详细介绍正在发生的事情,但是这段代码会生成许多文件,每个文件一个月,其中一个包含平均值。

每月以以下格式显示

...
0,65,78,32.65
0,65,79,35.09
0,65,80,31.14
0,65,81,42.7
0,65,82,49.57
...

这些值分别表示:月份,纬度,经度和降水。 对于平均值,除了省略第一个条目外,它看起来几乎相同。

...
59,94,59.874165
59,95,65.954994
59,96,57.805836
...

现在,我们已经获得了易于使用的格式的数据,可以使用它来创建可视化。

加载生成的CSV文件

要加载文件,我们只使用一个简单的XMLHttpRequest,如下所示:

// create an XMLHttpRequest to get the datavar xmlhttp = new XMLHttpRequest();xmlhttp.onreadystatechange = function() {if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {var coords = CSVToArray(xmlhttp.responseText,",");// and process each of the coordinates...}}// make the call and use the callback to process the resultxmlhttp.open("GET", "location/of/the/file", true);xmlhttp.send();

现在,coords变量包含所有坐标,并为每个坐标显示值。 实际上,将其转换为画布非常容易。

将CSV数据处理到世界网格中

在XMLHttpRequest的回调中,我们检查是否已接收到数据并将其转换为一组坐标。 我们唯一需要做的就是将这些坐标转换为画布上的可视化图像。

var coords = CSVToArray(xmlhttp.responseText,",");coords.forEach(function(point) {var offset = 0;if (point.length > 3) {offset = 1;}if (parseFloat(point[2+offset]) >= 0) {var lat = parseInt(point[0+offset]);var lon = parseInt(point[1+offset]);var value = parseFloat(point[2+offset]);if (value > max) max = value;// lat is from 0 to 180// lon is from 0 to 360var x = canvas.width/360*((lon)-180);if (x<=0) {x=canvas.width-(x*-1);}var y = canvas.height/180*lat;if (value >= 0) {context.beginPath();context.rect(x,y,4,4);context.fillStyle = scale(value).hex();context.fill();}}});

如您所见,非常简单的代码就是我们将位置取下来,将它们转换为画布上的X和Y坐标,并创建具有特定颜色的小方块。 为了生成颜色,我们使用Chroma.js比例尺。

var scale = chroma.scale(['red' , 'yellow', 'green', 'blue']).domain([1,1700], 100, 'log');

此调用创建从红色到黄色到绿色到蓝色的色标。 值的范围是1到1700,分为100步,并使用对数刻度。 这将产生以下图像(这次是2012年1月的降水:

由于我们拥有所有月份的数据,因此我们现在可以轻松创建简单的动画。

动画化两个月之间的过渡

对于动画,我们将创建类似于以下电影中所示的内容,其中我们在各个月份之间缓慢过渡:

只需将图像彼此叠加显示并更改不透明度,即可轻松创建此动画。 因此,首先设置一些css,它将大部分图像隐藏起来,然后将它们全部放在另一个顶部。

#cf {position:relative;margin:0 auto;height: 700px;}#cf img {position:absolute;left:0;width: 1600px;}

现在我们可以添加图像,并使用“ bottom”类仅显示第一个图像:

<div id="cf"><img id="img-1" class="top" src="./assets/images/2012-01-perc.png" /><img id="img-2" class="bottom" src="./assets/images/2012-02-perc.png" /><img id="img-3" class="bottom" src="./assets/images/2012-03-perc.png" /><img id="img-4" class="bottom" src="./assets/images/2012-04-perc.png" /><img id="img-5" class="bottom" src="./assets/images/2012-05-perc.png" /><img id="img-6" class="bottom" src="./assets/images/2012-06-perc.png" /><img id="img-7" class="bottom" src="./assets/images/2012-07-perc.png" /><img id="img-8" class="bottom" src="./assets/images/2012-08-perc.png" /><img id="img-9" class="bottom" src="./assets/images/2012-09-perc.png" /><img id="img-10" class="bottom" src="./assets/images/2012-10-perc.png" /><img id="img-11" class="bottom" src="./assets/images/2012-11-perc.png" /><img id="img-12" class="bottom" src="./assets/images/2012-12-perc.png" />
</div>

现在,我们只需要一些JavaScript即可将所有内容捆绑在一起:

var month=[];month[0]="January";month[1]="February";month[2]="March";month[3]="April";month[4]="May";month[5]="June";month[6]="July";month[7]="August";month[8]="September";month[9]="October";month[10]="November";month[11]="December";var allTweens;init();animate();function init() {// create a chain of tweensallTweens = setupTweens(12);allTweens[0].start();}function setupTweens(imageCount) {var tweens = [];for (var i = 0 ; i < imageCount ; i++) {var tween = new TWEEN.Tween( { opac: 0, image: i, max: imageCount } ).to( { opac: 100 }, 2500 ).easing( TWEEN.Easing.Linear.None ).onUpdate( function () {// on update, lower the opacity of image i and update the opacity of// image i+1;var currentImage = document.getElementById('img-'+(this.image+1));if (this.image == imageCount -1) {var nextImage = document.getElementById('img-'+1);} else {var nextImage = document.getElementById('img-'+(this.image+2));}currentImage.style.opacity = 1- this.opac / 100;nextImage.style.opacity = this.opac / 100;} );tween.onComplete(function() {document.getElementById('title-2012').textContent = "Showing precipitation: " + month[this.image] + " " + 2012;// Set the inner variable to 0.this.opac = 0;// we're done, restartif (this.max-1 == this.image) {allTweens[0].start();}});// connect to each anotherif (i > 0) {tweens[i-1].chain(tween);}tweens.push(tween);tweens[0].repeat();}return tweens;}function animate() {requestAnimationFrame(animate);TWEEN.update();}

在这里,我们使用tween.js设置图像之间的过渡。

作为奖励:还可以创建图例以显示什么颜色表示什么

在动画中,您可以在底部看到图例。 此图例创建为简单的画布,另存为图像。 为了完整起见,此处显示执行此操作的代码:

var canvas = document.createElement("canvas");canvas.width = 435;canvas.height = 30;var context = canvas.getContext('2d');var domains = scale.domain();document.body.appendChild(canvas);// from 1 to 1700for (var i = 0 ; i < domains.length ; i++) {context.beginPath();context.rect(10+i*4,0,4,20);console.log(domains[i]);context.fillStyle = scale(domains[i]).hex();context.fill();}context.fillStyle = 'black';context.fillText("0 mm", 0, 30);context.fillText(Math.round(domains[25]) + " mm", 100, 30);context.fillText(Math.round(domains[50]) + " mm", 200, 30);context.fillText(Math.round(domains[75]) + " mm", 300, 30);context.fillText("1700 mm", 390, 30);

在这里,我们只使用我们更容易看到的比例,并遍历各个域以创建彩色图例。

参考: 使用HTML5,Canvas创建全球降水(降雨)可视化,并从Smart Java博客的JCG合作伙伴 Jos Dirksen 打开数据 。

翻译自: https://www.javacodegeeks.com/2014/02/create-global-precipitation-rain-visualizations-with-html5-canvas-and-open-data.html

初始化创建画布

初始化创建画布_使用HTML5,画布和开放数据创建全球降水(雨)可视化相关推荐

  1. 使用HTML5,画布和开放数据创建全球降水(雨)可视化

    我目前正在为Three.js编写下一本书,其中一章涉及可视化开放数据. 在寻找可以使用的数据时,我遇到了来自NOAA的一组数据. 通过此站点,您可以以网格格式下载一组全世界的每月降水报告. 因此,我下 ...

  2. 画布式编程_构建HTML5画布游戏如何帮助我学习编程

    画布式编程 by Surbhi Oberoi 由Surbhi Oberoi 构建HTML5画布游戏如何帮助我学习编程 (How building HTML5 canvas games helped m ...

  3. 如何用mysql创建数据仓库_数据仓库入门(实验1)创建数据源

    首先需要创建一个数据源,SSAS(分析服务)将利用数据源来连接源数据库.一.准备环境1.准备SQLServer 安装一台SQLServer2012.2.安装DEMO数据库 下载一个演示 首先需要创建一 ...

  4. h5画布动画_使用HTML5画布制作动画的漫画面板

    h5画布动画 Continuing the comic theme I've been building over the past few weeks and inspired by the new ...

  5. css画布星空_使用HTML5画布制作星空背景

    css画布星空 Because it works on a pixel-by-pixel basis, canvas is perfectly suited to making extremely d ...

  6. html5画布插入图片,html5画布导入图片

    Canvas是在html5中新出现的元素,目前支持的有chrome浏览器,360和ie都不支持,标签如下 style="border:1px solid #c3c3c3;"> ...

  7. python创建系列_一起学python系列之类(创建和使用类)

    在做欧几里得的几何时,证明一个简单的结论,有时候直接甩出公理出来就可以了,再后碰到复杂的,公理不够用了(这意味着你要根据公理从头到尾推一遍),直接甩出定理来解决数学里的几何问题,类也是这种效果. 面向 ...

  8. maya python 创建求_如何使用python在Maya中创建列表

    预期输出 我想在Maya 2014中创建一个用户界面,其中包含图像中给定的图层和相机.我不知道该使用什么小部件.我尝试创建,代码如下所示.在import maya.cmds as cmds windo ...

  9. three.js创建光线_使用Three.js在图像上创建波动效果

    three.js创建光线 View demo 查看演示Download Source 下载源 Waves! Because who does not enjoy the visual comfort ...

最新文章

  1. 气计算,人工智能高度发达的未来世界
  2. SPOJ Ada and Spring Cleaning(hash)
  3. c语言 10以内加法,求助 给小学生出题,自己选加减乘除 做10题 10以内的数 然后统计分...
  4. C语言再学习 -- 分支与跳转语句
  5. 统计学 计算机论文,统计学课程论文范文
  6. k8s 配置dashboard
  7. 中文字符频率统计python_使用 Python 统计中文字符的数量
  8. 把UIView提到所有View的最前面
  9. mysql存储过程的优缺点,数据库篇(二)——什么是存储过程?有哪些优缺点?...
  10. 35 个非主流数据库
  11. 分布式任务调度框架设计与实现解读(1)
  12. spine 导出纹理_Spine入门 —— 纹理打包
  13. 机器学习——验证方法
  14. word 插入mathtype公式对象后,默认环绕方式是浮于文字上方,每次插入后都得手动改成嵌入,如何解决?
  15. 几何光学学习笔记(17)- 4.6光学材料
  16. 说极路由牛逼的人们,你们用过Tomato DualWAN吗?(二)
  17. 鸿蒙有什么大劫,封神大劫之后,七大准圣排名
  18. springboot引入国际化
  19. 黑莓手机屏幕发展历程对比 blackberry 各型号屏幕大小
  20. IT是未来大趋势,有学计算机专业的同学会后悔和转行原因在哪?

热门文章

  1. HDU5875 - Function
  2. 线段树专题-黑白棋盘 BZOJ-1453
  3. Network of Schools POJ - 1236 tarjan强连通分量缩点
  4. Spring 自动装配 ‘byName’
  5. 《白鹿原》金句摘抄(三)
  6. 1-10 之间的整数相加,得到累加值大于 20 的当前数
  7. Servlet使用适配器模式进行增删改查案例(jdbc.properties)
  8. 服务器windows系统如何登陆,如何登陆windows云服务器
  9. 转:Java 7 种阻塞队列详解
  10. thinking-in-java(20)注解