什么是Nodebox?

Nodebox是一种基于Python,开源,不需要编码,只拖拽节点就可以通过数据驱动生成复杂可视化图形的工具。

软件能力

数据驱动生成静态或动态图形,图形可以以png,svg单帧或序列的形式导出。

开源,可由用户创建自定义节点。

界面

左侧为生成图形区,勾选Origin在十字线中心显示的即为坐标系原点(0,0);勾选Bounds即显示画布边缘(也即导出图片的边缘),画布大小可以在Files>Document Properties中设置。

右上为节点参数区,在此调节节点的参数。

右下为节点拖拽区,在这里通过New node按钮添加新节点。

节点

作为Nodebox的核心,节点是最重要的部分。

在左侧的生成图形区默认会显示最新添加的节点的内容,这个区域不仅会显示图形,也会显示节点运算后的数据结果。

节点按照颜色分为六大类,上部是输入端,下部是输出端,输入端与输出端均有数据类型限制。

深蓝色是数据源操作节点,输出类型为Data(table);

浅蓝色是Data操作节点,输出类型为List;

灰蓝色是点处理节点,输出类型为points(通常为一对或多对坐标值,坐标值数据类型为浮点型,实际上是一个数组);

灰色节点为计算节点,输出类型为整型或浮点型,可能是单个数字,也可能是一个数组;

紫色为颜色节点,输出RGB或HSB色值(其实也是数组,数据类型为浮点型);

黑色为几何节点。Nodebox的绘图节点,输出几何图形。

节点数据类型详解:

https://www.nodebox.net/node/documentation/concepts/concepts.html

Nodebox中各节点的设计比较黑盒,用户不需要特别精确地掌握每个节点的输入输出类型,多试几次会有意想不到的结果。

实例一:Earth Quake

该图形反映了地区-震级和伤亡人数的关系。

从官网数据实例和教程:

https://www.nodebox.net/node/documentation/using/data-visualization-debtris.csv

https://www.nodebox.net/node/documentation/using/data-visualization.html

也可以下载我制作的.nbdx文件和数据文件:EarthQuake.ndbx;data-visualization-earthquakes.csv;我的数据文件经过排序,和官网略有不同。以下为教程转载:

总体来说这个教程没什么难度,主要就是体验一下使用nodebox建立图形的一些思路

Create an import csv node and point to the csv file.

Create a lookup node and set Key to Region. Connect import_csv1 to it.

Create a textpath node. Set Align to Left. Connect lookup1 to Text.

The result so far is all information as text on top of each other. Next procedure will build the template to be used as points to translate all these different textpaths on.

Create an ellipse node. Set Width and Height to 500.0.

Create a resample node. Set Method to Amount. Connect ellipse1 to Shape.

Create a count node and connect import_csv1 to it. We will use this number to figure out what degree each segment needs and to create a range to multiply it to this segmentsize.

Create a divide node. Set Value1 to 360.0. Connect count1 to Value2. Out comes the segment.

Create a range node and send count1 to End.

Create a multiply node. Connect range1 to Value1 and divide1 to Value2.

Now we need a few transformation nodes to connect this data to the actual data.

Create a rotate node. Connect multiply1 to Angle. Connect textpath1 to Shape.

Create a translate node. Connect rotate1 to Shape and resample1 to Points.

Render translate1.

Have a look at the csv file and notice that it has a lot of columns. Let’s add the depth and magnitude to it.

Create a lookup node and set Key to Depth.

Create a divide node to enable scaling of the number. Connect lookup2 to Value1.

Create a rect node. Connect divide2 to Width. Set Height to 5.0.

Create an align node and connect rect1 to it. Set HAlign to Right.

Finally create a combin node to store all shapes in them before the transformation nodes (rotate and translate). Then send this combined shape to rotate1.

You can change the second value of the divide node to make the rectangles longer.

Create a lookup node and set Key to Magnitude. Connect import_csv1 to it.

These are all rather small numbers so let’s create a multiply node. Connect lookup3 to Value1 and set Value2 to 5.0.

Create an ellipse node and connect multiply2 to Width and Height.

Now we need the location of the rect we’ve been using to visualize the depth parameter. It can be retrieved from divide2 which we used to give rect1 a height.

Create a negate node and connect divide2 to it.

Create a make point node and send negate1 to X.

Create a translate node. Connect make_point1 to Points and ellipse2 to Shape.

我使用的数据经过了排序,所以看起来和官网图形不同。这也是数据驱动生成图形的意义所在,即使只是排序不同,在图形生成上也会有很多不同。

实例二:A Zipmap example

该图形将Metallica专辑中出现的高频词按年份进行了分组。

同样下载数据集,并按照教程拖拽节点:

附件中我的.nbdx文件:ZipMap.nbdx;data-visualization-metawords.csv

这篇教程里zipmap节点和translate节点的功能需要一些理解,我在和后面会详细说到。

https://www.nodebox.net/node/documentation/using/data-visualization.html

Create an import csv node and look for the csv file.

Create a lookup node. Set Key to Word and connect import_csv1 to it.

Create a textpath node and connect lookup1 to text. Select a font and set font size to 14. Set Align to Left and the x value of Position to 100.0.

Now we will place them on a circle.

Create a count node and connect lookup1 to it.

Create a range node and connect count1 to End.

Create a multiply node. Connect range1 to it and set Value2 to 6.

Create a rotate node. Connect textpath1 to Shape and multiply1 to Angle.

Render rotate1.

ok,到这里都没有问题

In the second section we will create a set of points based on the number of albums. Note that the datafile points to the year in which the album was released. We will than decide that word from one album all go to the same point and that for each word.

Create a lookup node. Set Key to Year.

Create a distinct node. Connect lookup2 to it. Distinct removes all duplicates, what remains are 9 years each standing for one album.

Create a count node. Connect distinct1 to it.

The idea is to generate a number of points. We will do this be using a rect node connected to a scatter node.

Create a rect node. Set its dimensions to 500 * 500.

Create a scatter node. Connect rect1 to Shape. Connect count2 to Amount. We now have 9 points.

Create a zipmap node. Connect distinct1 to Keys and scatter1 to Values.

Create a lookup node. Connect zip_map1 to List and lookup2 to Key.

The viewer pane will reveal only the same set of points but if you switch to data view you will see that each point has multiple points behind it (at the same location).

We will glue these two together.

怎么样?这里是不是有什么不对了?

是的,官网教程这部分使用的是自定义节点,节点功能是未知的,而我们没有这个节点。

Create a translate node. Connect rotate1 to Shape and lookup3 to Translate.

如果把distinct1节点和ZipMap1,lookup2和lookup3节点直接相连,lookup3节点中是不会有任何数据的,后面的translate1节点也就会受到影响,没有图形产生。

所以这部分应该修改成这样:

zipmap1的key和lookup3的key输入时,都应先转换为整型。

zipmap就是将Key和Value合并为一个list;

使用了一个make string节点用于观察lookup3中的数据内容(增加观察节点是一种常见的编码思路,类似于js中的print函数,就是为了验证其他函数输出的结果。)

画出9个点,却从make string节点输出了一大堆数据,说明了什么问题?仔细看make string中的数据,1983年份的坐标都是一样的。

也就说是,lookup3中画出的看似是九个点,实际上是按年份分组的一堆点。观察数据源,比如1983年有48个高频词数据,在lookup3 1983年的坐标位置上重叠绘制了48个点,只是它们看上去是一个点,那么为什么要这么画呢?这和后面translate1节点的运用有很大关系。按年份分组的这一堆坐标,是为textpath1中的每个高频词元素提供了一个偏移量。

Create an integer node. Connect distinct1 to it.

Create a textpath node. Connect integer1 to it. Select a type and a fontsize of 24.0.

Create a translate node. Connect textpath2 to Shape and scatter1 to Translate.

所以translate节点并非移动每个大图形的中心点,而是移动每个元素的位置。

Create a combine node. Connect translate1 to list1 and translate2 to List2.

Render combine1.

教程大概就是如此,第二个稍微需要进行一些思考,如果有啥问题欢迎和我们联系。