The Interactive & Immersive HQ

Table DAT Operator in TouchDesigner

The Table DAT operator in TouchDesigner stands out as a remarkably versatile tool for organizing and manipulating data in immersive projects. This article showcases some of the many uses of the Table DAT operator, illustrating its ability to not only manage text strings and scripts but also serve as a dynamic control center for parameters, network communications and, of course, component replication.

Defining Multiple Strings of Text

One of the fundamental uses of the Table DAT is to manage text strings, which can then be dynamically displayed using a Text TOP and referencing the table in the DAT property of the Text TOP. By storing a series of text strings in a Table DAT, is possible to create dynamic systems where text changes in response to various triggers or interactions. In this example, integrating a Keyboard In CHOP with a Count CHOP allows the selected text row to change based on user input, providing a simple and quick way to interact with text in real-time projects.

Example Step-by-Step

  1. Let’s create a Table DAT and populate it with the desired text strings, each in a separate row.
  2. Add a Keyboard In CHOP to capture user input followed by a Count CHOP to keep track of input events.
  3. Link the Count CHOP to the Table DAT, setting it to control the row index. Each time the Keyboard key is pressed, the count number changes, changing the string of text displayed.

Script and Expressions Storage and Execution

One of my favorite uses of the Table DAT operator is storing and executing scripts and Expressions. It is a real game-changing approach to managing project organization. This method not only centralizes script management but also allows for the dynamic execution of Python scripts and TouchDesigner expressions based on various events or interactions. In this simple example, by connecting a CHOP Execute DAT to a Count CHOP, is possible to cycle through different expressions stored in the Table DAT, executing them as needed by pressing a key. This setup provides a modular and flexible approach to scripting, allowing easy project scalability.

Example Step-by-step

  1. First, let’s fill a Table DAT with various scripts, ensuring each occupies its own row. In this case I am updating a different property of my Text TOP with each line.
  2. Next, we add a Count CHOP to navigate through these scripts, triggered by an event like a keyboard press.
  3. Finally, using a CHOP Execute DAT we can run the currently selected script, dynamically altering the project’s behavior.

The script used in this example is:


def executeScript(row):
    script = op('table_dat')[row, 1].val  
    exec(script)

currentRow = op('count_chop')['chan1'].eval() 
executeScript(currentRow)

Let’s break down this script.

def executeScript(row):

defines the function executeScript based on the row number passed to it.

script = op('table_dat')[row, 1].val  
    exec(script)

Access the script in the in the table DAT mentioned, but ignoring the first column (that in this example was used to store the name of the script

currentRow = op('count_chop')['chan1'].eval() 
executeScript(currentRow)

Retrieves the current value of the ‘chan1’ channel from the CHOP named ‘count_chop’, and assigns this value to the variable currentRow. The second line assigns this value as an argument for the expression previously defined: executeScript effectively allowing for the execution of different scripts based on the real-time value of the ‘chan1’ channel in ‘count_chop.

Parameters Change Visualization and Network Communication Log

The Table DAT’s functionality extends to logging and visualizing network communications and parameter changes, particularly useful for continuous data streams like sensor readings. By employing custom scripts within callback DATs, incoming data can be organized and displayed within a Table DAT in a clear and manageable manner. This approach is critical in projects where there’s a need for real-time data monitoring and manipulation in cases where a constant stream of data is hard to parse.

For the following example, we are trying to parse serial readings from a humidity and temperature sensor. Using a script within a serial callback DAT that organizes data by their name is possible to assign temperature and humidity readings to specific rows and columns in the table DAT, making it much easier to monitor and use the data within the project. This approach can be applied to data streams of way more complexity.

Example Step-by-step

  1. First, direct incoming serial data to a script using the callback DAT.
  2. Create the Table DAT that will be receiving the parsed data for real-time monitoring.
  3. In the script, parse the incoming data and use conditional logic to organize it into the appropriate rows and columns of a Table DAT based on content (e.g., “temperature” vs. “humidity”).

The Script used for this example is:

def onReceive(dat, rowIndex, message, bytesReceived):

    targetTable = op('visualize_data') 


    if targetTable.numRows == 0:
        targetTable.appendRow(['Temperature', 'Humidity'])


    if "Temperature:" in message:
        temperature = message.split("Temperature:")[1].strip()
 
        if targetTable.numRows < 2:
            targetTable.appendRow([temperature, ""])
        else:
            targetTable[1, 0] = temperature 
 
    elif "Humidity:" in message:
        humidity = message.split("Humidity:")[1].strip()
       
        if targetTable.numRows < 2:
            targetTable.appendRow(["", humidity])
        else:
            targetTable[1, 1] = humidity 

Let’s break down this script.

def onReceive(dat, rowIndex, message, bytesReceived):

Make sure this script is only executed when a message is received in the Serial Monitor

    targetTable = op('visualize_data')

Reference the target Table DAT where you want to store the organized data. In this case my Table DAT was called “visualize_data”.

    if targetTable.numRows == 0:
        targetTable.appendRow(['Temperature', 'Humidity'])

Initialize the target Table DAT with headers if it’s empty.

  if "Temperature:" in message:
        temperature = message.split("Temperature:")[1].strip()

Parse the message based on its identifier. In this case is Temperature.

if targetTable.numRows < 2:
            targetTable.appendRow([temperature, ""])

Ensure there is always a row to update, add one if necessary.

        else:
            targetTable[1, 0] = temperature

Update the temperature in the second row, first column.

    elif "Humidity:" in message:
        humidity = message.split("Humidity:")[1].strip()

        if targetTable.numRows < 2:
            targetTable.appendRow(["", humidity])
        else:
            targetTable[1, 1] = humidity

Parse the message based on its identifier. In this case is Humidity, followed by making sure there’s always a row to update and add one if necessary, and finally update the humidity in the second row, second column!

Get Our 7 Core TouchDesigner Templates, FREE

We’re making our 7 core project file templates available – for free.

These templates shed light into the most useful and sometimes obtuse features of TouchDesigner.

They’re designed to be immediately applicable for the complete TouchDesigner beginner, while also providing inspiration for the advanced user.

Configuration and Preset Management

Probably, one of the most common uses for Table DATs is to hold data that can dynamically generate content. This application is particularly useful for managing visual and audio parameters that spreads throughout multiple levels of a network, allowing for quick switches between different project states or configurations. By structuring configurations within a Table DAT, users gain the ability to update their projects to various states with minimal effort.

Example Step-by-step

  1. First, create Table DAT with rows and columns representing different configurations and their respective parameters.
  2. In this example, instead of relaying in scripts, we are using a select DAT and we are taking the value of the count CHOP to select which row of data is being applied to the circle.
  3. Finally, reference each column the select DAT unique row to the properties we wat to modify.

Integration with Replicator COMP

No review of the versatility of the Table DAT operator is complete without including its integration with the Replicator COMP. The Replicator COMP creates copies of a component, one for every row in a table. It’s been called the “for-loop” of operators. The main component to be replicated itself can be as complex of a network as the project requires and the copies (called “replicants”) are dynamic and automatically updated whenever there’s a change in the table.

Example Step-by-step

  1. Begin by creating a Container COMP. This will serve as the foundation of your network. Inside this container, build out the network with all the components you need for your project.
  2. Outside of the container, set up a Table DAT with all the parameters that will be modified in each distance. Each row in the Table DAT is dedicated to a distinct state or configuration. Next, reference the values on the first row, for example, to each one of the parameters they are intended to modify inside your Container COMP
  3. The final step is integrating the Replicator COMP. By setting the ‘Master Component’ to reference the main Container COMP, the Replicator COMP is informed of the component to duplicate. Linking the ‘Template DAT Table’ to the Table DAT then guides the Replicator COMP on the unique attributes each replicant should adopt, based on each row in the Table DAT.

For an overview of other TouchDesigner DATs, check out our tutorial:

Conclusion

The Table DAT in TouchDesigner is pretty much a game-changer for anyone looking to keep their projects organized and dynamic. From juggling lines of text to managing complex scripts and settings, this tool has got you covered. Through the examples we’ve walked through, it’s clear how versatile and handy the Table DAT can be. Whether you’re organizing data, tweaking your project on the fly, or even just laying out the structure of your project, it’s amazing what you can achieve with the Table DAT in projects with many moving parts.