关于此教程 | 基础 | 安装 | 增加元素 | 链式语法 | 绑定数据 | 使用数据 | 用div绘制柱状图 | data()魔法 | SVG初步 | 绘制SVG | 数据类型 | 制作柱状图 | 制作散点图 | 尺度 | 坐标轴 | |

更新时间: 2012-12-30


D3对输入数据的处理极为灵活。这次的主题是JavaScript和D3中常用的数据结构。

变量

变量就是数据项,它是数据的最小构造单元。变量也是所有其它数据结构的基础,即变量的不同配置构成不同的数据结构。

如果你初次学习JavaScript,首先要了解的是它是一门宽松类型(loosely typed)的语言,意思是,你不需要预先指定变量的类型。与之相对的是很多强类型(strong typed)的语言,比如Java(两者名字相近,但完全不同,基本没关系),要求声明变量时指定类型,比如int,float,boolean,或String

//Declaring variables in Java
int number = 5;
float value = 12.3467;
boolean active = true;
String text = "Crystal clear";

而JavaScript,却是根据赋值内容自动地获取变量的类型。比如,''""表示字符串类型,我习惯于使用双引号,但有些人则喜欢单引号。

//Declaring variables in JavaScript
var number = 5;
var value = 12.3467;
var active = true;
var text = "Crystal clear";

老是var,var,var,是不是很无聊?但是却极为方便,因为我们可以在知道数据类型之前就将其声明出来。你甚至可以随时更改一个变量的类型,指定不同类型的值即可。

var value = 100;
value = 99.9999;
value = false;
value = "This can't possibly work.";
value = "Argh, it does work! No errorzzzz!";

数组

数组只不过是值的序列,为方便起见,将多个对象或数值存储在一个连续的空间中,并用一个变量来表示。若不用数组,类似于下面这种为每个值声明一个变量的方法是很没效率的

var numberA = 5;
var numberB = 10;
var numberC = 15;
var numberD = 20;
var numberE = 25;

如果用数组存储了这些值,则代码简单多了。数组内容用中括号[]来包围起来,数组的值之间用逗号分隔。

var numbers = [ 5, 10, 15, 20, 25 ];

数据可视化中数组无处不在,所以你应该适应它并且非常熟练才行。访问数组中的值也使用中括号:

numbers[2]  //Returns 15

中括号中的整数表示数组中的位置。需牢记的是,数组的位置总是从0开始的,即第1个元素是0,第2个元素是1,依此类推。

numbers[0]  //Returns 5
numbers[1]  //Returns 10
numbers[2]  //Returns 15
numbers[3]  //Returns 20
numbers[4]  //Returns 25

有些人想出一些巧记的办法,比如,将数组视为一张具有空间位置,拥有行和列的表格

 ID | Value
 ------------
  0  |  5
  1  |  10
  2  |  15
  3  |  20
  4  |  25

数组中可以存储任意类型的数据,而不仅仅是整数。

var percentages = [ 0.55, 0.32, 0.91 ];
var names = [ "Ernie", "Bert", "Oscar" ];

percentages[1]  //Returns 0.32
names[1]        //Returns "Bert"

数组和for循环

基于编程的数据可视化肯定是少不了数组和for()循环的。它们是数据控的动感二重奏。(你大概不会承认自己是数据控,但是我不得不提醒一下,你现在看的这篇文档题为”数据类型”哟)

数组用一个变量组织大量的数据值。而for()则可以快速地循环访问数组中的每个值,然后执行相应的操作,比如,将值表达为图形形式。D3的神奇的data()方法本质上做了同样的事情,但有时候手动编写循环代码也是很重要的。

我不会解释for()循环的详细机制,因为再来一章才能说得清楚。这里,仅用一个示例来描述如何循环访问numbers数组。

for (var i = 0; i < numbers.length; i++) {
	console.log(numbers[i]);  //Print value to console
}

看到numbers.length没有?这个语法是不是很优美?如果numbers长度为10,则此循环体中的代码会执行10次。如果长度为10亿,你懂的。这正是计算机擅长的:接受许多许多的指令,然后一直执行下去。这也是数据可视化的核心价值所在,你只要设计了和编码实现了可视化系统,系统会对不同的数据作出不同的响应。虽然数据可以发生变化,系统的映射规则却是不变的。

对象

数组可以很好地存储数据列表,但是对于更复杂的数据集,你就需要用到对象(object)了。你可以将JavaScript对象理解为定制的数据结构。我们使用大括号{}来表示对象。大括号中间是索引/值的二元组序列。索引和值之间用冒号:分隔,而二元组之间用逗号,分隔。

var fruit = {
	kind: "grape",
	color: "red",
	quantity: 12,
	tasty: true
};

为了引用对象中的值,我们使用点记号,后面接上索引名称

fruit.kind      //Returns "grape"
fruit.color     //Returns "red"
fruit.quantity  //Returns 12
fruit.tasty     //Returns true

可以理解成”值”属于”对象”。看,这儿有一个水果。你会问”这是什么类型的水果?”。而回答是fruit.kind,值为"grape"。你又问”好吃否?”。那是必须的,因为fruit.tasty值为true

对象+数组

将数组和对象结合起来得到对象的数组,数组的对象,或对象的对象。根据你的数据集内容,你可以定制任意合理的数据结构。

比如,我们有了更多的水果,水果的分类体系需要相应地进行扩展。我们在最外层使用中括号[],表示这是一个数组,而在里面使用大括号{},里面包含的是一个对象,对象之间用逗号隔开。

var fruits = [
    {
        kind: "grape",
        color: "red",
        quantity: 12,
        tasty: true
    },
    {
        kind: "kiwi",
        color: "brown",
        quantity: 98,
        tasty: true
    },
    {
        kind: "banana",
        color: "yellow",
        quantity: 0,
        tasty: true
    }
];

访问这个数据时,我们只需要根据索引就可以获得其中一个对象的值。强调一下,[]表示数组,{}表示对象。因此,fruits是一个数组,因此,首先要用索引获得数组中的一个元素:

fruit[1]

接下来,因为每个数组元素都是一个对象,因此可进一步用句点来获得对象的成员:

fruit[1].quantity   // Returns 98

下面的映射给出了fruits对象数组中每一个值

fruits[0].kind      ==  "grape"
fruits[0].color     ==  "red"
fruits[0].quantity  ==  12
fruits[0].tasty     ==  true

fruits[1].kind      ==  "kiwi"
fruits[1].color     ==  "brown"
fruits[1].quantity  ==  98
fruits[1].tasty     ==  true

fruits[2].kind      ==  "banana"
fruits[2].color     ==  "yellow"
fruits[2].quantity  ==  0
fruits[2].tasty     ==  true

显然,我们共有fruits[2].quantity个香蕉。

JSON

在你的D3生涯中,你很有可能会遇到JavaScript对象记号(JavaScript Object Notation),详细内容参考维基百科。不要想太多,JSON只不过是将数据组织成JavaScript对象的一种特定的语法。这种语法针对JavaScript(显然)和AJAX请求进行了优化,因而,你在基于web的API中看到很多JSON数组也就不足为奇了。相比于XML,JSON解析起来更快,也更容易,因此,D3没有理由不支持。

说了那么多,JSON的样子也不会比我们刚才见过的东西更古怪

var jsonFruit = {
    "kind": "grape",
    "color": "red",
    "quantity": 12,
    "tasty": true
};

唯一区别在于,所有的成员索引都用双引号包围起来了,让它们本身也变成了字符串。

GeoJSON

JSON是JavaScript对象的规范化,而GeoJSON是JSON对象的进一步规范化语法,它主要针对地理数据进行了优化。所有的GeoJSON对象都是JSON对象,而所有的JSON对象都是JavaScript对象。

GeoJSON可以在地理空间中存储点(即经纬坐标),它还可以存储形状(如线和多边形)和空间特征。如果你有大量的地理数据,你最好是将它们转换为GeoJSON,D3对GeoJSON支持地很好。

在介绍地图时,我们会详细介绍GeoJSON。现在,只要知道简单的GeoJSON数据长什么就行了。

var geodata = {
    "type": "FeatureCollection",
    "features": [
        {
            "type": "Feature",
            "geometry": {
                "type": "Point",
                "coordinates": [ 150.1282427, -24.471803 ]
            },
            "properties": {
                "type": "town"
            }
        }
    ]
};

容易混淆的是,经度总是放在纬度前面。因此,习惯用”经/纬”思考问题,而不是”纬/经”。中文好像没这个问题,我们总是习惯说”经纬度”而不是纬经度。另外,将”经度”方法视为x方向也是顺理成章的吧。

上一篇: 绘制SVG
下一篇: 制作柱状图