Introduction to Python Tutorial

From TouchDesigner Documentation
Jump to: navigation, search

This tutorial is a general introduction to using Python in TouchDesigner. Resources for learning Python in general are here.

Inputting Python[edit]

Python in the Textport[edit]

The simplest method to input Python scripts is through the textport. The textport, like all scripting in TouchDesigner, allows scripts to be specified in either Python or Tscript.

After opening the textport, make sure it is set to Python language. This is controlled by the small toggle button in the upper left side of the textport.

When it is set to Py, all input is interpreted as Python. When set to T it is interpreted as tscript.

In addition the textport prompt and text color have different values for each language, making it easier to identify which state the textport is in:

TextportPython.png TextportTscript.png

As a simple test type the following into the textport:


This will output all help related to the op() method found in the td Module.

The td Module is the main module containing all TouchDesigner related classes and objects. It is imported by default when the application begins.
Another useful module is the tdu Module. This module contains some specific TouchDesigner utility functions useful during scripting.

Python in DAT Scripts[edit]

Though multiple line scripts can be entered into the textport, they are generally stored in a DAT, such as a text DAT.

Begin by placing down a new Text DAT. Make sure the operator's parameter language mode is set to Python. This is done by clicking the Operator Language button, located in the upper right corner of the operator dialog.

Python Mode Tscript Mode

This mode controls the language of both the DAT contents, and its parameter expressions. In cases where the two use different languages are used, modify the Language parameter on the common page accordingly.

Click the Viewer Active Flag to edit its contents.

Enter the following two line script:

for i in range(1,5):

Note the first line should not include any leading spaces in this example, while the second line is indented. It should either be indented with a single tab or 4 spaces.

A single script can not mix indentation methods.

To run the script, right-click on the node and select Run Script from the popup menu.


The output will be echoed to the textport. Open the textport to see the digits 1 through 4 printed.

Importing Modules[edit]

Part of the great power of Python is its access to the countless number of modules that have been created. The default installation includes all standard modules.
For example, open the textport and type:

import math

This will import the default math module from the installation folder, making its methods available.

Modules not included by default may also be imported. Examples of other useful Python modules are here. Unofficial precompiled modules found on Christoph Gohlke's website.

This is done most easily through the following steps:

  • Install a parallel copy of the same version of Python to the hard disk.

The current version of Python shipped with TouchDesigner is 3.7. It can also be found here.. Python generally installs to location: C:/Python37

  • Ensure the module you wish to use, is compatible with Python 3.7. Also ensure it is compatible with the specific version of TouchDesigner you are running (32 or 64 bit).
  • Install the module to the parallel python installation (eg C:/Python37).
  • Launch C:/Python37/python.exe and import the module manually to make sure there are no errors.

Once the module is successfully installed, it will automatically be visible by TouchDesigner by default. This option is found under the Edit->Preferences menu as "Add External Python to Search Path". Alternatively you can add the search path by modifying the Preference labelled "Python 32/64 bit Module Path". Multiple paths are separated by semicolons (;). Finally you can modify the search path directly by either modifying the system environment variable PYTHONPATH or be executing a script which appends the path to sys.path as in the example below.

import sys
mypath = "C:/Python37/Lib/site-packages"
if mypath not in sys.path:

Overriding built in modules[edit]

TouchDesigner may come with specific modules pre-installed. If you require a different version, find the TouchDesigner folder where the original is included and remove it from the search path before importing.


import sys
sys.path.remove('C:\\Program Files\\Derivative\\TouchDesigner\\bin\\lib\\site-packages')

Creating Internal Modules from DATs[edit]

Python allows scripts to be organized as modules. This is done through the standard import statement. In TouchDesigner the module can reside on disk like regular Python or they can also reside inside other DATs.

Place down a text DAT and rename it to my_utils. Ensure its parameter language is set to Python, activate its viewer, and enter the following function:

def my_adder(x,y):
	return 10*x+y

In the same component, add another text DAT. Rename it to test_import and ensure its parameter language is set to Python as well. In this DAT enter the following:

import my_utils
a = my_utils.my_adder(1,3)

After running this script, the value of 13 will be printed in the textport. The my_utils DAT has been treated as a module, through the import statement above.

Component Modules[edit]

Just as TouchDesigner allows for Component Variables, and Component Time, so too can one create Component Modules. These are simply DATs placed in a specific child of the component, namely its local/modules component.

Module Search Order[edit]

When attempting to import a module, TouchDesigner first searches in the current component for a DAT with that module name.
If it is not found, it then searches its component modules.
If still not found, it then searches the component modules of each parent until it reaches the root component.
If still not found, it then searches the component modules of /sys component.
If still not found, it then searches the regular Python disk search.

In this manner, one can place component modules at a specific parent location and know they will be found by all children and sub-children of that component. For example, any DATs placed in /local/modules will be accessible to all scripts and expressions wherever they are located.

Note: When you attempt to import an external module, it will first look for DATs of that name in the same folder , so be sure to avoid name conflicts keeping the above search order in mind.

Module On Demand[edit]

The import statement, though useful contains two disadvantages:

  • Module names must be single words, so relative DAT paths cannot be used.
  • They are unsuitable for use in a parameter expression.

To avoid this, use the Module On Demand or mod object.

In the DAT test_import, replace the contents with the following code:

a = mod.my_utils.my_adder(1,3)

Notice how no import statement is needed, making this evaluation suitable for parameters. The same search rules apply when using the module on demand object.

Finally, string paths, including relative paths may be used. Simply pass in the string as a parameter to the mod object:

a = mod('my_utils').my_adder(1,3)

Both absolute and relative paths may be used:

a = mod('/project1/my_utils').my_adder(1,3)

All versions will result in the same output.

Working with Operators[edit]

Basic access[edit]

The main class type describing any Operator is the base OP Class. You will need a reference to one of these to do anything. There are two global operator objects are always available (except for in the Textport):

  • me refers to the operator that is currently being evaluated or executed. For example, when executing a script, me refers to the containing DAT. When evaluating an expression, me refers to the containing operator.
  • root refers to the top level component /.

To get references to other OPs (for example, a node named 'wave1' sitting next to the node 'constant1') the most common functions to use are: op() and ops(), for example op('wave1').

op() returns a single OP object, while ops returns a (possibly empty) list of OPs. They are described in td Module.

These functions search for operators from the current component, so both relative and absolute paths are supported. The current component is defined as: The OP that me is inside.

Note that the OP Class itself, also contains an op() and ops() method. In this case, nodes are searched from the OP.

For example: me.op('..') will always return its own parent, while op('..') will return the parent of the current component.

If you are typing a python expression in a parameter of a node 'constant1', and you wish to get a reference to 'wave1', you would type


If you are in a script you can assign this reference to a variable for easier repeated access.

n = op('wave1')

In this case op() will search relative to the DAT that is executing the script.

An OP also has a parent() method that can be use to get the parent COMP of it.


If you are putting a Python statement in a parameter of a COMP and want to refer to a child of that COMP, you can use the op() method for the OP, which is available as me in the parameters.


TIP: To find out quickly what members and methods you have access to for any node, select that node and on its parameter dialog, click the Python Help icon. You will go the wiki for the python classes for that node. There you can find out what info you can get about a node, and what methods are available for it. The documentation can also be arrived at by right clicking on the node and selecting "Python Help..." from the menu.


Place down a new Text DAT, ensure its parameter flag is set to Python, and enter the following script:

n = op('/project1')
m = n.ops('text*')
for a in m:

After running the script, n is assigned the results of the global function, while m is assigned results relative to n.

Some useful members and methods of an OP object, are:

  • name
  • path
  • children
  • parent()

These are described in OP Class. Notice the last attribute, parent() is a function. It takes an optional argument specifying how far up the parent chain to climb. To see how they are used in practice, put down a new Text DAT, ensure its Parameter Language parameter is set to Python and enter the following code:

print('i am ', me)
print('child of ', parent())
print('grandchild of ', parent(2))

print('root children:')
k = root.children
for r in k:

The resulting details will be found in the textport.

Common Python Tasks[edit]


Creating an OP (Sphere SOP) op('/project1').create(sphereSOP)
Creating a named OP op('/project1').create(sphereSOP, 'mysphere')
Copying OPs (Nodes) op('/project1').copy(op('out1'), name='out2')
Deleting an OP op('mysphere').destroy()
Renaming an OP op('mysphere').name = 'thesphere'
Changing an OP's type op('mysphere').changeType(boxSOP)
Changing multiple OPs' types list = ops('*sphere*')
[s.changeType(boxSOP) for s in list]
Setting an OP's comment op('mysphere').comment = 'this is a sphere'
Changing an OP's parameter op('mysphere').par.frequency = 10
Changing an OP's parameter
with more than 1 value
s = op('mysphere')
s.par.tx = 1
s.par.ty = 2 = 3
Pulsing a parameter value op('moviein1').par.cue.pulse()
Cooking an OP op('mysphere').cook()
Saving an OP's data to a file op('mysphere').save('sphere.tog')
Changing an OP's Render and Display Flags on s = op('mysphere')
s.render = True
s.display = True
Loading a .tox file into a COMP op('/project1').loadTox('geo1.tox')
Wiring operators together Refer to the Connector Class
Clicking gadgets (panel components) op('slider1').click(.6, .7)
Timeline Play/Pause = True/False


Querying another OP's parameter op('sphere1').par.tx
Querying a parameter in the same OP me.par.tx
Getting Info CHOP channels from an OP
without cooking it
Getting an OP's parent parent()
Getting an OP's grand-parent parent(2)
Getting an OP's name
Getting an OP's parent's name parent().name
Getting digits of an OP's name in its parameters me.digits
Getting digits of an OP's parent's
name in its parameters
Getting digits of another OP's name op("moviein1").digits
Getting an OP's type # returns an op object, not a string
getting a unique random number each frame tdu.rand(absTime.frame+.1)
getting a unique random number per numbered operator tdu.rand(me.digits+.17)
Checking for an OP's existence if op('moviein1'):



Getting the number of children of a COMP len(op('geo1').children)
Getting the number of inputs of a multi-input OP len(op('switch1').inputs)
Getting Info CHOP channels from an OP, width is a member op('moviein1').width
Conditional "if" in one line of a parameter 22 if me.time.frame<100 else 33
Conditional "if" alternative [33,22][me.time.frame<100]
Convert space separated string to a list tdu.split('Space separated string with "two word item"')
List comprehension [ for c in root.children]
Conditional list comprehension [ for c in root.children if != 'perform']
Test operator type type(root) == baseCOMP
Test operator family isinstance(root, TOP)


"Absolute Time" is the time since you started your TouchDesigner process, not counting when your power button was off (top bar).

Retrieving a node's local frame number me.time.frame
Retrieving a node's local time in seconds me.time.seconds
Retrieving absolute time in frames absTime.frame
Retrieving absolute time in seconds absTime.seconds

Storage in Python[edit]

Storage is the preferred way to work with persistent global data in Python, since it can store anything data type.

Setting a value in storage of a component n'keyname', 0.0)
Getting a value from storage n.fetch('keyname')
Directly access the storage dictionary
Directly access a key in the storage dictionary['keyname']
Test if a key exists in the storage dictionary 'keyname' in


Variables are always text strings.

Setting a value me.var('DESKTOP')
Setting a Root Variable root.setVar('MEDIA', 'c:/MEDIA')
Setting a Component Variable
at the current component
parent().setVar('MEDIA', 'c:/MEDIA')
Setting a Component Variable
at another component
op('/project1/geo1').setVar('MEDIA', 'c:/MEDIA')
Setting a Path Variable Set the Path Variable parameter of any parent component and use me.var('name') in the same way.

Print versus Debug[edit]

The above code makes uses of the built in print function. The debug statement can be used to obtain more specific information about a python object, and will also append the line number and script in which debug was called.

Simply replace all occurrences in the above example to obtain more detailed information:

debug('i am ', me)
debug('child of ', parent())

debug('root children:')
k = root.children
for r in k:

The debug function can be used anywhere the print function is used.
Alternatively, one could always print identifying attributes specific to the object: me.path etc.

Python in Parameter Expressions[edit]

Begin by placing down an Geometry Component. Make sure the Geometry Object is called geo1 and its Language Parameter is set to Python (as described earlier).

Toggling this flag will automatically convert all existing parameter values to the specified language where it can.

In its Translate X parameter (first) field enter:


The resulting expression now evaluates to 13.

Similarly, a parameter can refer to another parameter value from any location, including the same operator. This is done through the Par Class. Its main access is eval(), val and expr.
In the above field, change the expression to:


Now the Translate X value will contain whatever is in the Translate Y (second) field. Modify the Y value to confirm.
As Parameter objects are automatically converted to numbers or strings when needed, the above can be shortened to:


Quotes and String Constants[edit]

All python parameter fields are always treated as expressions, so when entering a string constant, it must be contained within single or double quotes, otherwise it will be interpreted as a specific python object, resulting in an error.

For example, in the material parameter of geo1. Setting it to:
phong1 will result in an error, as phong1 cannot be found.
It must be therefore be set to: 'phong1' to denote a literal string constant.
The interface to the string parameter fields will be changed in the future to avoid this requirement.

Scripting Parameter Values[edit]

In addition to manually entering parameter values and expressions, they may also be scripted. Place down a new Text DAT. Ensure its parameter language is set to Python.

In the Text DAT enter the following:

n = op('geo1')
v = n.par.rx.eval()
n.par.rx.val = 30

When run, the current value of rx parameter of geo1 will be printed, then changed to 30.
In this case, the eval() call explicitly returns the parameter value, but it can automatically be evaluated as needed in many cases:

#examples of automatic casting
v = float(n.par.rx)
v = n.par.rx + 5          
v = n.par.rx * n.par.ry

Similarly, the same method can be used to directly set the value of a parameter without using the set method:

n.par.rx.val = 5
n.par.rx = 5

This class may also be used to set the parameters expression. In the above example change the last line to:

n.par.rx.expr = 'me.time.frame'

Run this code, and notice the rx parameter is now set to the current frame, by referring to the operator's Time Component

Things to Note Regarding Python and Tscript[edit]

Operators can be in Tscript mode or python mode by setting their Operator Language flag on the parameter. Some old files opening in 099 may have their nodes in tscript mode to keep things compatible, but any new nodes created in 099 are in python mode by default. Default Node Language can be changed in preferences.

A dialog box in which commands and scripts can entered manually. Script errors and python print() messages are also output to the textport.

TouchDesigner's original built-in Command scripting language prior to Python.

An Operator Family that manipulates text strings: multi-line text or tables. Multi-line text is often a command Script, but can be any multi-line text. Tables are rows and columns of cells, each containing a text string.

A set of commands located in a Text DAT that are triggered to run under certain conditions. There are two scripting languages in TouchDesigner: Python and the original Tscript. Scripts and single-line commands can also be run in the Textport.

The location of an operator within the TouchDesigner environment, for example, /geo1/torus1, a node called torus1 in a component called geo1. The path / is called Root. To refer instead to a filesystem folder, directory, disk file or http: address, see Folder.

An Operator Family that contains its own Network inside. There are twelve 3D Object Component and eight 2D Panel Component types. See also Network Path.

Any of the procedural data operators. OPs do all the work in TouchDesigner. They "cook" and output data to other OPs, which ultimately result in new images, data and audio being generated. See Node.

An Operator Family that contains its own Network inside. There are twelve 3D Object Component and eight 2D Panel Component types. See also Network Path.

TouchDesigner Component file, the file type used to save a Component from TouchDesigner.

The panel at the bottom of TouchDesigner, it controls the current Time of the full system or just one component.

An Operator Family which operate on Channels (a series of numbers) which are used for animation, audio, mathematics, simulation, logic, UI construction, and many other applications.

An Operator Family that creates, composites and modifies images, and reads/writes images and movies to/from files and the network. TOPs run on the graphics card's GPU.

Storage is a python dictionary associated with any operator, used to keep user-specified data within the operator.

The component types that are used to render 3D scenes: Geometry Component contain the 3D shapes to render, plus Camera, Light, Ambient Light, Null, Bone, Handle and other component types.