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 Python basics cheat sheet of 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.
TouchDesigner Python Cheat Sheet
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, file path in the project, or the current settings of its parameters, this set of expressions can help retrieve that info.
Description | Python Expression | Example Result |
Getting an OP’s Path relative to the root | op('text1').path | /project1/text1 |
Getting an OP’s name | op('text1').name | text1 |
Get the last digit (or digits) in an OP’s name | op('json8Fmt24').digits | 24 |
Get the base portion of an OP’s name before the last digit(s) | op('json8Fmt24').base | json8Fmt |
Querying the value of an OP’s parameter | op('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.
Description | Python |
---|---|
Creating an OP | op('/project1').create(textDAT) |
Creating an OP with a specific name | op('/project1').create(textDAT, 'textJson') |
Copying OPs | op('/project1').copy(op('textJson'), name='textJson2') |
Deleting an OP | op(' |
Renaming an OP | op('textJson').name = 'textData' |
Changing an OP’s type | op('textData').changeType(jsonDAT) |
Setting an OP’s comment | op('textData').comment = 'This DAT contains test weather data for the project' |
Changing an OP’s parameter | op('noise1').par.seed = 10 |
Pulsing a parameter value | op('timer1').par.start.pulse() |
Cooking an OP | op('base1').cook() |
Modifying an OP’s Render and Display Flags | op('box1').render = True |
Connecting operators together | op('ramp1').outputConnectors[0].connect(op('feedback1')) |
Run Python code after a delay | run('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.
Description | Python Expression | Example Result |
---|---|---|
Retrieving a node’s local frame number | me.time.frame | 102.0 |
Retrieving a node’s local time in seconds | me.time.seconds | 1.6833333333333333 |
Retrieving absolute time in frames | absTime.frame | 2036595 |
Retrieving absolute time in seconds | absTime.seconds | 33942.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.
Description | Python Expression | Example Result |
Evaluate channel chan1 at the current frame | op('noise1')['chan1'].eval() | 0.21917423605918884 |
Get sample 2 of channel chan1 | op('noise1')['chan1'].eval(2) | 0.2202223539352417 |
Get the number of CHOP Channels | op('noise1').numChans | 5 |
Get the CHOP length | op('noise1').numSamples | 600 |
Get the third sample from the first channel | op('noise1')[0][2] | 0.2202223539352417 |
Get the name of the 2nd channel | op('noise1')[2].name | chan3 |
Get the channel index of channel chan1 | op('noise1')['chan5'].index | 4 |
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.
Description | Python Expression |
Get a cell value by index | op('table1')[1,2] |
Get a cell value by label | op('table1')['position1', 'tx'] |
Get a cell value by row index, col label | op('table1')[1, 'ty'] |
Get the number of table rows | op('table1').numRows |
Get the number of table columns | op('table1').numCols |
Set a cell value by indices or labels | op('table1')[3,4] = 0.24163 ‘position1 ‘
|
Set a cell value by label | op('table1')['position1', 'tx'] = |
Copy a table to another table | op('table1').copy(op('fromTable')) |
Append a row to a table | op('table1').appendRow([label, 'xPos','yPos']) |
Append a column to a table | op('table1').appendCol(['tz', pos1tz, |
Clear a table’s contents | op('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
Description | Python Expression | Example 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
# results in 0.18462683260440826, will be the same every time
|
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)
|
Remap an input value from an initial range to a new range | remap(inputVal, fromMin, fromMax, toMin, toMax) | tdu.remap(0.75, 0, 1, -180, 180) |
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?') |
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:
- Introduction to Python Tutorial
- Python Tips
- Working with OPs in Python
- Category:Python Reference
- Python Classes and Modules
- tdu Module
You can also watch this tutorial, where Elburz discusses Python optimizations and tips for TouchDesigner:
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!