The Interactive & Immersive HQ

Python Cheat Sheet for TouchDesigner Developers

For new TouchDesigner developers, keeping all of the different Python members and methods specific to TouchDesigner can be somewhat of a challenge, especially if they’re not already experienced with coding. Add the vast amount of functionality that Python has built-in (much of which is very useful for developing projects as well), and you’ve got a lot to contend with!

In this post, we’ve collected a cheat sheet of Python tricks and tips that are useful for TouchDesigner developers to know, including several that are built into Python itself, as well as a large number that are specific to the TouchDesigner environment.

Cheat Sheet for Python

This section is by no means complete, and could honestly be a multi-post topic of its own, but here’s a few functions we’ve found to be useful in development of TouchDesigner projects.

For advanced developers, the functionality in this section is intended to be more beginner-oriented, especially for those who are just starting to learn Python. The next section features a much larger list of members and methods specific to TouchDesigner.

Casting / Type Conversion in Python

x = int(4.5245)  # x will be 4
y = float(6)  # y will be 6.0
z = str(101.65)  # z will be '101.65'

Although a straightforward and commonly used component of Python, you’ll find yourself returning to this series of functions often in TouchDesigner. Although TouchDesigner is often pretty good about automatically casting certain values for you, there are situations where you might want to convert data between different types (especially when you’re working with parameters, operator names, or writing extensions).

As you’d expect int() will result in an integer number, and if being given a float value will remove all the decimals (meaning no rounding will happen). float() provides you with a float number. And string() provides you with a string — which can contain a lot of different data types, including strings, floats, and integers!

Rounding in Python

round(float, number of decimal places)
x = round(5.242375, 2)  # x will be 5.24

Another simple but no less useful function, round() allows you to specify a number to be rounded and the number of places to round the decimal place to. This can be useful for control signals or even for displaying numerical values via the Text TOP.

Working with Strings

Manipulating and formatting strings for different purposes is another common task when building projects in TouchDesigner. There are actually many functions related to this topic, so we’re going to cover a couple of common ones.

F-String Formatting

Formatted string literals or f-strings for short are a relatively recent addition to Python, and have proved to be an extremely useful way of quickly formatting strings, requiring less code than previous methods. To use this method, first prefix a string with f or F, followed by single quotes ' ' around the string itself. Then you can add replacement fields, which are expressions placed inside of curly braces {}. The expressions within the curly braces will be evaluated and added to the final string. Take a look at the example below.

pi = 3.14159
piStr = f'π is roughly {pi:.2f}' # piStr evaluates to 'π is roughly 3.14'

As you can see in this example, you can easily insert variables into strings with this technique. You also may have noticed another useful aspect of f-string formatting, you can utilize an optional format specifier after the expression to control how the value is formatted. In this case, we’ve added :.2f after pi to round the variable to two decimal places. If we wanted three decimal places, we could use pi:.3f instead. The format specifier is always placed after a : following the variable.

String Replace

string.replace(oldvalue, newvalue, count)

Sometimes it’s helpful to replace a portion of a string with another string, and that’s what the replace function is all about. You can even control the number of occurrences of the old value you want to replace (by default it will replace all occurrences). Take a look at the example below:

txt = 'The bus was a dark green color'
x = txt.replace('dark green', 'light blue')
print(x) # x prints as 'The bus was a light blue color'

Uppercase, Lowercase, Capitalization

string = 'TEst'
print(string.upper()) # this prints 'TEST'
print(string.lower()) # this prints 'test'
print(string.capitalize()) # this prints 'Test'

If you ever need to format your text so that it is all uppercase, all lowercase, or has the first letter capitalized, Python has you covered! Upper() converts a string to uppercase, lower() converts it to lowercase, and capitalize() capitalizes the first letter. Pretty convenient!

Python also has functions that allow you to check whether a string is lowercase (isLower()) or uppercase (isUpper()). One thing to note about all of the functions in this section is that they take no parameters, so in practice you’ll utilize them as illustrated above.

Cheat Sheet for TouchDesigner-Specific Python Functionality

Now, on to expressions and functions that are specific to TouchDesigner itself! Derivative have included many useful utility members and methods for just about anything you can think of in TouchDesigner, so just like the last section, the content we’re covering here really only scratches the surface of what’s available.

Retrieving Information From Operators

If you’re looking to get information about an operator, including its name, path in the project, or the current settings of its parameters, this set of expressions can help retrieve that info.

DescriptionPython ExpressionExample Result
Getting an OP’s Path relative to the rootop('text1').path/project1/text1
Getting an OP’s nameop('text1').nametext1
Get the last digit (or digits) in an OP’s nameop('json8Fmt24').digits24
Get the base portion of an OP’s name before the last digit(s)op('json8Fmt24').basejson8Fmt
Querying the value of an OP’s parameterop('noise1').par.seed.eval()1.0
Accessing an OP’s Parent
Note that the above shortcuts will also work here, such as parent().name, parent().digits, etc.
op('noise1').parent()/project1

Working With Operators

In the case that you’re looking to modify OPs (rather than retrieving info about them) this set of expressions will be useful.

DescriptionPython
Creating an OPop('/project1').create(textDAT)
Creating an OP with a specific nameop('/project1').create(textDAT, 'textJson')
Copying OPsop('/project1').copy(op('textJson'), name='textJson2')
Deleting an OPop('textJson').destroy()
Renaming an OPop('textJson').name = 'textData'
Changing an OP’s typeop('textData').changeType(jsonDAT)
Setting an OP’s commentop('textData').comment = 'This DAT contains test weather data for the project'
Changing an OP’s parameterop('noise1').par.seed = 10
Pulsing a parameter valueop('timer1').par.start.pulse()
Cooking an OPop('base1').cook()
Modifying an OP’s Render and Display Flagsop('box1').render = True
op('box1').display = False
Connecting operators togetherop('ramp1').outputConnectors[0].connect(op('feedback1'))
Run Python code after a delayrun('op("timer1").par.start.pulse()', delayFrames=60)

Time

Absolute Time is defined as the time since TouchDesigner was started, but does not continue counting when the power button in the menu bar is turned off. Generally, it is used to provide an ever-increasing value which can be used in a number of creative ways, including for generative effects. It’s commonly paired with Noise transformation parameters.

DescriptionPython ExpressionExample Result
Retrieving a node’s local frame numberme.time.frame102.0
Retrieving a node’s local time in secondsme.time.seconds1.6833333333333333
Retrieving absolute time in framesabsTime.frame2036595
Retrieving absolute time in secondsabsTime.seconds33942.25

Accessing CHOP Data

Working with CHOP data is a near ubiquitous task in TouchDesigner, whether you’re a beginner or seasoned developer. There are many useful Python expressions that allow access to useful information, well beyond the values of the channels themselves.

DescriptionPython ExpressionExample Result
Evaluate channel chan1 at the current frameop('noise1')['chan1'].eval()0.21917423605918884
Get sample 2 of channel chan1op('noise1')['chan1'].eval(2)0.2202223539352417
Get the number of CHOP Channelsop('noise1').numChans5
Get the CHOP lengthop('noise1').numSamples600
Get the third sample from the first channelop('noise1')[0][2]0.2202223539352417
Get the name of the 2nd channelop('noise1')[2].namechan3
Get the channel index of channel chan1op('noise1')['chan5'].index4

Working with DAT Data

Like CHOPs, DATs are another commonly used tool in the TouchDesigner toolbox. There are many ways to work programmatically with them , whether you’re looking to add data, manipulate already existing cells, or remove all content besides the labels.

DescriptionPython Expression
Get a cell value by indexop('table1')[1,2]
Get a cell value by labelop('table1')['position1', 'tx']
Get a cell value by row index, col labelop('table1')[1, 'ty']
Get the number of table rowsop('table1').numRows
Get the number of table columnsop('table1').numCols
Set a cell value by indices or labelsop('table1')[3,4] = 0.24163
op('table1')[2, 'label'] =
position1
op('table1')['tx', 1] = 3
Set a cell value by labelop('table1')['position1', 'tx'] = 0.24163
Copy a table to another tableop('table1').copy(op('fromTable'))
Append a row to a tableop('table1').appendRow([label, 'xPos','yPos'])
Append a column to a tableop('table1').appendCol(['tz', pos1tz, pos2tz])
Clear a table’s contentsop('table1').clear()
Clear a table’s contents, but keep the first row (can also use keepFirstCol = True to keep first column, and keepSize=True to keep the table’s size but delete all the content in the cells)op('table1').clear(keepFirstRow = True)

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.

The TDU Module: A Variety of Useful Python Utilities

The TDU module is a bit of a grab bag of functions that are useful in a variety of different TD contexts. You’ve probably seen tdu.rand() before, but there are definitely more options well worth looking into. For the sake of not making an already long post even longer, we’re not covering them all here, so if you’re interested in taking a deeper dive, check out the reference page on the TDU module in the wiki: https://docs.derivative.ca/Tdu_Module

DescriptionPython ExpressionExample Result
Return a random value in the range [0.0, 1.0), given an input seed value. The output will never reach 1.0, but may produce 0.0. For a given seed, it will always give the same random number. Seed inputs do not need to be numbers.tdu.rand(seed)1. tdu.rand(me)
# for text1 DAT, results in 0.7499504089355469 and will be the same every time

2. tdu.rand(5)

# results in 0.18462683260440826, will be the same every time

3. tdu.rand(absTime.frame) # results in 0.1743839979171753, will change every frame
Clamp a value between min and max values. Arguments can be any type that allows comparison (float, int, str, etc).tdu.clamp(inputVal, min, max)1. tdu.clamp(7.35, 0, 6)
# results in 6


2. tdu.clamp('c', 'a', 'b')
# results in 'b'


3. tdu.clamp(6, 5, 5.55)
# results in 5.55
Remap an input value from an initial range to a new rangeremap(inputVal, fromMin, fromMax, toMin, toMax)tdu.remap(0.75, 0, 1, -180, 180)
# remap from 0-1 range to angle, results in 90.0
Format a string to be suitable for an operator name. Converts illegal characters and slashes to underscores.tdu.validName(str)tdu.validName('text-dat$%JSON?')
# returns 'text_dat__JSON_'

The above information is mostly adapted from the Derivative wiki for TouchDesigner, which is an indispensable tool for wrapping your head around the Python members and methods that the software offers. If you’re interested in diving deeper into Python in TouchDesigner, it’s well worth checking out the following wiki articles:

Wrap-Up

That was a bit of a whirlwind! I hope that this post illustrates how tightly integrated Python is within the TouchDesigner environment, and provides a useful resource for some of the common Python members and methods that you’ll return to more and more as you gain experience developing projects in TouchDesigner. Happy programming!