# Experimental:ParGroup

## ParGroup

A ParGroup is a group of related parameters. It is often more natural to work with the ParGroup as a whole instead of its individual [[Par Class|parameters].

Often all parameters sharing the same line on a parameter dialog belong to the same ParGroup.
For example, in the Transform TOP, *Translate* is a type of ParGroup, with two primary Par objects: *tx*, *ty* and a unit Par.

ParGroups with only single elements are also possible.
For example, the *Uniform Scale* parameter of the Geometry Object belongs to a ParGroup with only one parameter.
Note that ParGroups with multiple elements only contain numeric elements.
Strings only exist in ParGroups of size 1.

### Basic Usage

The following example assumes *n* is a Transform TOP with its translate set to *1, 2*
Like *n.par*, *n.parGroup* can be used to access individual ParGroup objects:

```
t = n.parGroup.t # assign t to the Translate ParGroup
```

From here, most of the members and methods available to Par objects are also available to ParGroup objects. Instead of returning one value however, they return a tuple of values where applicable.

```
t.expr # returns (None, None) if the translate parameter has no expressions set
```

### Evaluation

```
t.eval() # returns (1, 2)
```

Note that if the ParGroup contains only a single element, such as the *Uniform Scale* parameters, its *eval()* method still returns a tuple and not a single value:

```
n.parGroup.scale.eval() # returns (1.0,)
```

### Size, Mapping and Iteration

```
len(t) # returns 2, as this ParGroup contains 2 primary parameters. The unit parameter is ''not'' included here.
t[1].name # returns 'ty', since t[1] return Par object ty.
[i.name for i in t] # returns [‘tx’, ‘ty’] #primary parameters only
[i.name for i in t.pars()] # returns [‘tx’, ‘ty’, 'unit'] #all parameters
```

The pars method is identical to OP.pars, and returns **all** parameters in this ParGroup, primary or otherwise.

### Assignment

ParGroups can be assigned a single value (a scalar) or a tuple of the same size.
Note in the following examples, both tuples () and lists [] are interchangeable.
In some cases though, using list syntax is less ambiguous: *[3] vs (3,),* since *(3)* is not a tuple.

```
n.parGroup.t = (4, 5) #assign tx=4, ty=5
n.parGroup.t = [4,5] # any iterable object of size 2 will do
n.parGroup.t = 5 #assign 5 to tx, ty
n.parGroup.t = n.parGroup.p #assign pivot values to translate parameter.
n.parGroup.t = (1,2,3) # error, cannot assign 3 elements to 2.
```

Note that the above also works when assigning directly to the Parameter val members:

```
n.parGroup.t.val = (1,2)
```

### Arithmetic

ParGroups can be used in some arithmetic expressions directly, as operations are applied pairwise:

```
n.parGroup.t + 1 # returns (2.0, 3.0)
n.parGroup.t + (1,2) #returns (2.0, 4.0)
```

To ensure forward compatibility though, it is best to create ParGroup objects where applicable:

```
tdu.Vector(n.parGroup.t) + (1,2) #returns a Vector with values 2.0 4.0
```

### Unit and Pulse Parameters

Sometimes a ParGroup will end with a parameter of a different type on the same line, such as a unit menu or a pulse button.

In this case, the ParGroup is actually a subclass, such as *ParGroupUnit* or *ParGroupPulse*.
These subclasses contain members to access these extra parameters:

```
m = op(‘timer1’).parGroup
m.parGroup.length.unit.val = ‘seconds’ # set the unit parameter
```

m.parGroup.cue.pulse() # pulse the applicable parameter

### Casting

Casting a ParGroup to a bool will always raise an exception, as the ParGroup will always be a non-empty tuple, thus normally returning *True*. This could lead to confusion where bool(n.parGroup.button) always returns *True*, leading one to assume the button value itself is true.

Casting a ParGroup to a float or int however, will only succeed if that ParGroup contains exactly 1 element, as in the case of a *Uniform Scale* for example:

```
5 + float(n.parGroup.scale)
```

This also means *op('geo1').parGroup.scale* for example, can be used in a single parameter expression expecting a numeric avlue.

Furthermore, the global functions *any()* and *all()* work as expected, given that ParGroups behave like tuples:

```
any(n.parTuple.t) # true if any of tx,ty,tz non-zero
all(n.parTuple.t) # true if all of tx,ty,tz non-zero
```