Monday, March 28, 2016

Data Matching and Data Trees in Grasshopper

An understanding of data matching and data trees is critical to successfully developing more complicated definitions in Grasshopper. This post will help you understand these concepts.
The Grasshopper examples (and corresponding Rhino file) shown below can be downloaded here. You can disable all the components in the definition, then Enable those in a single group to see its effect.

Data in Grasshopper

Data in Grasshopper can be single values, lists of values, or what are known as trees of data.

Single Value

A single value is obvious, for example the output of a number slider is single value. You can see this when you wire it into a panel:

You can also see this in the wire itself - it is shown as single solid line which indicates a single value.

Here's another example. The single value is fed into the radius of a Circle component. A single plane specifies the plane to draw the circle on. The result is one circle drawn.

List of Values

A list of values results when a component outputs several values. An example is the Series component which outputs, well, a series of numbers. The user specifies a start value, and an increment for one value to the next, and a total count of values. In the example below the series starts at 1, is incremented by 2, with a total number of values of 3.

The Panel shows the output values, 1, 3, 5. Also note the wire is shown as double lines indicating the data is a list rather than a single value. The Series is wired into a Circle component which uses the value as a Radius. The result is three circles of radius 1, 3, and 5.

There are some components commonly used with lists. List Item returns a single item in the list. List Length returns the number of items in the list. Usage of these is shown below:

Tree of Data

A tree of data is output when a hierarchy is involved in the data. It's called a tree because the data is organized into separate branches. A simple example is when you use the Rectangular component to create a grid of cells/points, each column in the grid is in an independent branch. In the rectangular grid below there are 4 columns and 6 rows. The tree has four branches (one for each column). In each branch is a list of 6 items. A circle is drawn at every point. 

Grasshopper provides tools to help you visualize data trees. First, note the wire coming out of the grid is drawn as a dashed line. That always means the data is in the form of a tree. There is a component called the Param Viewer which lets you visualize the structure of the tree.

The Param Viewer shows there are 4 branches, where each one has 6 elements (N=6). The Param Viewer has a right-click menu option to draw the tree graphically.

With that enabled you see a graphic representation of the tree. Note it only shows the 4 branches, not the "leaves" (the list of 6 items in each branch).

Another tool useful in visualizing a tree like this is the Point List component. When there is a tree or a list of points, Point List labels them in the Rhino viewport by using numeric text to show the position in the list of each point. Here it is wired in, with a slider to set the text size, shown in Grasshopper and the viewport.

It's very important to note the following; There are four branches, each with six points. The Point List shows quite clearly that each branch is independent of the others. The points in each branch are labelled 0 to 5. Then the numbering starts over again at 0 again. Why? Because each branch of the tree is independent of the others. The data is not shared between or across branches. Therefore the Point List shows them independent of one another.

This independence of the branches is usually very useful. It can also be controlled by using specialized components to manipulate the branch structure. Your skill in using these components has a big impact on your overall skill with Grasshopper in general.

There are some common components used with data trees. These are Flatten and Graft. Have a look at the Param Viewer examples below to see the structure of each tree after being processed by Flatten and Graft.

This component converts the data from a tree into a list. It removes the hierarchy information entirely. The grid point labeling, after flattening, looks like this:

As you can see the hierarchy is gone and the points are numbered in order, 0-23.

This component takes every leaf in the tree and makes it its own branch. Since the branches are independent, the point list is all 0's. That's because as soon as it labels one point it starts a new branch and the labels its first point. There's always one per branch.

Flip Matrix
This component flips a "matrix-like" (think two dimensional grid or array) data tree by swapping the rows and columns. Note how the numbering is flipped so the columns climb in value (where previously the rows climbed in value):

Data Matching

This section discusses what data matching is and why it is important to understand.

Components in Grasshopper automatically handle wired-in single values, lists, as well as trees.

  • A component will process a single value once. 
  • A component will automatically loop or iterate over a list and process each element in the list. 
  • A component will automatically loop over a tree, dealing with each branch independently, and process each value or element in the list in the leaves of each branch. 
But what happens when a component is required to process both a list of values and a single value? Or a list and a tree? Whenever a situation like that arises, data matching is involved. This term refers to how the single value and the list of values are matched up and processed. Or how a list of values and trees of values are matched up and processed. Some simple examples will make this clear. You'll be introduce to the Grasshopper components which give you precise control over the processing.

Data Matching Lists of Points

The first few examples shows two lists of points. These points are fed into a Line component which takes two endpoint inputs and draws a line between them. One list is shorter (has less data) than the other.

A series component generates a list of values which become points with different Y coordinates. A second series generates another list of Y values, however these points are shifted one unit in X. These two lists are wired into the Line component which draws the line between them. This allows you to easily visualize the various types of matching between the two lists. Here's the simple definition:

Here's the result in the viewport - lines are drawn between points in the two lists:

As you can see, one list is shorter than the other. When Grasshopper does data matching to match up the values between the two lists, its default behavior is "longest list, repeat last". That means it uses the longest list for drawing the lines, thus there are 10 of them. It repeats the last item of the shorter list when it matches to the items in the longer list. This is the default behavior of Grasshopper.

There are two basic components which let you control data matching. Shortest List and Longest List. We'll look at Longest List first. The definition below is the same as the one above with the addition of a single Longest List component. As we saw above, longest list will repeat to the length of the longest list wired in. It has a right-click menu which let's you control how the repetition happens:

Longest List - Repeat First
You can see how the first item in the short list is repeated until there are enough items left to match up with the longer list.

Longest List - Repeat Last
This is the default case. You can see how the short list items are matched up with the longer list until they run out then the last item is repeated to match up with the remaining longest list.

Longest List - Interpolate
The items in the short list are uniformly distrubuted to the longer list. This results in four items being reused twice.

Longest List - Wrap
Here, after the shortest list items are used up they wrap back to beginning of that list and the matching happens from the beginning again.

Longest List - Flip
In this case, after the shortest list items are matched up, the longest list items starting matching back down, 7 to 5, 8 to 4, 9 to 3, and 10 to 2.

There's also a Shortest List component. In this case only the number of elements in the shortest list are matched up with those in the longer list. Right-click menu options let you choose between Trim End, Trim Start, and Interpolate. Here's the simple definition which demonstrates this:

Shortest List - Trim End
In this case the items at the end of the longest list are trimmed (not matched).

Shortest List - Trim Start
In this case, the items at the start of the longest list are trimmed (not matched).

Shortest List - Interpolate
In this case the items in the shortest list are distributed across the items in the longest list. As you can see this leaves four gaps in the matching but spans from the start to the end of the longest list.

Data Matching Shapes in a Loft

Here's an example that lofts three different shapes:

  • 0: Square
  • 1: Circle
  • 2: Ellipse

The various Longest List options are shown when repeating the 3 items 9 times

Longest List - Repeat First
The first shape, the square, is repeated 6 times, then the list is used. 

Longest List - Repeat Last
The three shapes are used, then the last shape is repeated 6 times. 

Longest List - Interpolate
Each shape is used repeatedly to spread out over the range. So three of the first, three of the second and three of the third. 

Longest List - Wrap
The three shapes are used, in sequence, over and over (square, circle, ellipse, square, circle...). 

Longest List - Flip
The three shapes are used in order, then in reverse order, then in order again (square, circle, ellipse, circle, square, circle, ellipse, circle, square). 

Data Matching between a Tree and List

The next example shows data matching between a tree and a list. The tree is generated by the Rectangular grid component. The list is generated by a Series component. These are wired into a Longest List component which is set to Warp. 

You can see the results below. As we've seen previously each branch is treated independently. The series of 4 radius values are wired into the Circle component. The radius values wrap, that is they turn back to the smallest value once the list is fully used. So they get bigger for the 4 values in the series, then start over small. This happens independently in each branch. 

Compare this to when the tree is flattened (converted to a list). Take Note: these type of conversions are very commonly used and so there are right-click menus on the sockets of nodes to flatten, graft, etc. without having to wire in a component each time. That's what's done below: 

Here's the result - the values continue wrapping across all the (former) branches. Once the first column is done the radius values continue at the bottom of the next column. 

What happens if we Graft the list - turning it into a tree - how would this affect the data matching? This is done below: 

Now the matching is occurring between four branches of the radius data and four branches of the grid point data. Each branch is matched up one for one, so the first branch gets a branch with the smallest value. The next branch with the next biggest value, and so on. 

A Practical Example

It's a common practice in digital fabrication to create objects using stack lamination. That's the process of making a representation of a 3D form by taking slices through it, cutting sheet material to match the outline of those slices, then stacking them up to form a representation of the object.

Here's an example of a figure sculpture produced from sheet acrylic using this method:

To keep the parts organized during the cutting and assembly it's important to keep contours that are on the same level of the form together.

Here's a simple example using a sphere, a block form, and a torus (donut). The definition contours the objects and lays them out for cutting. The contours are group by the object they are within and by the contour they are on within the object:

The definition lets you contour the object at a user specified spacing. Here the sphere is being contoured every 0.5":

What if you wanted to contour everything: the sphere, the block and the torus. You could copy all the components in the definition three times and assign a different object to each. But that's not necessary, the definition will work if you simply assign all three objects to the same Contour component. It works because Grasshopper organizes the data trees by object and also by contour. Each object will be its own branch in the tree. And each level in the contouring will be its own branch.


By understanding how Grasshopper matches data, and knowing the components which give you control over that matching, you can more quickly and successfully develop your definitions. This topic has presented the basics of dealing with single values, lists and trees and managing the flow of data between components.

If you'd like to read a more technical account of data trees written by Grasshopper developer David Rutten please see The Why and How of Data Trees.

1 comment: