数据

有各种各样的方法来访问 Observable 数据。但由于我们刚刚开始,让我们使用最简单的:文件附件

这个 notebook 有一个每日温度度数的 CSV 文件。我使用 Shift-Cmd-U 键盘快捷键连接它;你还可以通过拖放文件到“文件”窗格来附加文件,可以通过 notebook 菜单或单击上面的“回形针”来访问该窗格。
image.png
FileAttachment 函数只返回一个句柄,该句柄允许你选择所需的表达形式,例如 blob,a buffer 或(UTF-8 编码)文本。对于 CSV 文件,我们可以调用 file.text 以字符串形式获取对文件内容的承诺。
image.png
当然,更有用的是将文本解析为具有命名日期和温度属性的对象,这可以通过将文本传递给 d3.csvParse 来实现。(D3 加载在下面的附录中,使 notebook 中的每个单元格都可以使用。)

单击下面的数组检查对象。
image.png
当 Observable 隐式地等待跨单元的承诺时,我们必须等待 file.text 承诺,因为我们希望访问同一个单元格中承诺的值。

默认情况下,D3 不会执行类型推断,因此日期和温度属性都是字符串。这使得它们很难处理。例如,如果你尝试添加两个温度,它会将它们连接起来。哦!😝
image.png
要将这些字符串转换为日期和数字,需要将一个函数作为参数传递给 d3.csvParse。对每行调用此函数,以便根据需要操作行对象。更好的是,通过 d3.autoType 以自动推断类型。image.png
如果检查上面的数组,你将看到青色日期和温度(而不是蓝色字符串),确认类型转化成功。

让我们暂时偏离一下 Observable 单元格的语法。到目前为止,你只看到了可以命名或匿名的表达式单元格。这两种类型的单元格都可以检查,但是只能从其它单元格引用命名的单元格。
image.png
对于比简单表达式更复杂的代码,可以编写一个 block,它是一个或多个花括号包围的语句。与函数类似,块单元格只有在 returnyield 时才产生值。image.png
局部变量,如上面的 s ,对notebook的其余部分是不可见的;只有指定单元格的返回值可以从其它单元格访问。这样来,Observable 就类似于电子表格:每个单元格定义一个单一值。image.png
回到手头的任务,这里有一种更显式的方法来获取、解析和类型转换名为 data 的单元格中的 CSV 文件。如果数据与 d3.autoType 不兼容,可以采用这种方式。(如果不确定,不要依赖自动类型推断或参考文档。)
image.png
有了数据的方便表示,我们现在就可以开始工作了!例如,我们可以计算日期和温度的范围,以获得范围的概念。 image.png
正如我们之前看到的,我们可以把它注入到柱状图的例子中来快速了解温度分布。
image.pngimage.png
气候温和!啊,旧金山。🌤

在处理 Observable 中的数据时,一个微妙的考虑是将代码放在每个单元格还是单独的单元格中。一个好的经验法则是,单元格应该定义一个命名值,以供其他单元格(如上面的数据)引用,或者应该向读者显示一些信息(如本文、上面的图标或检查数据的单元格)。

这条规则的一个重要含义是,你应该避免单元格之间的隐式依赖关系,只取决于你可以命名的内容。

为什么?notebook 的 dataflow 是由它的单元格引用构建的。如果单元格没有名称,则不能引用它,并且隐式地依赖于其效果的单元格可能在它之前运行。(单元格按拓扑顺序运行,而不是从上到下。)隐式依赖导致不确定性行为😱在开发期间,和重新加载 notebook 时💥可能的错误。

例如,如果一个单元格定义了一个数组,而第二个单元格对其进行了就地修改,其它单元格可能会在突变之前或之后看到这个数组。为了避免这种不确定性,可以通过为第二个单元格提供一个名称并用 Array.fromarray.map 复制该数组来显示地实现依赖关系。或者合并这两个单元格,这样其他单元格就只能看到已经修改过的数组。

准备好我们的数据后,让我们转向图形!