How can I rename follicles for right and left using the translate X info?

Hi all, I’ve been working on code for a facial rig, currently I’m in the lips part working on a ribbon, but I haven’t managed to rename the follicles for right and left. I’m using the position of the follicle in X to know which side should be. At this moment this code is just a test to rename the follicles, I have a list, but apparently when I select more than one follicles it doesn’t work. Someone knows how can I make it work?

import maya.cmds as mc
import maya.mel as mel

selec = mc.ls(sl=True)

for i in selec:
sel = mc.select(i, add=True)
tx = mc.getAttr( sel[0] + ‘.translateX’)
print tx
if tx < 0:
mel.eval('searchReplaceNames “up_rb” “r_up_rb” “selected” ')
elif tx == 0.002:
mel.eval('searchReplaceNames “up_rb” “mid_up_rb” “selected” ')
else:
mel.eval('searchReplaceNames “up_rb” “l_up_rb” “selected” ')

You’re just getting the translateX position of the first item :slight_smile:
tx = mc.getAttr( sel[0] + ‘.translateX’)

Switch to using the i and it should work;
tx = mc.getAttr( i + ‘.translateX’)

This being said, there are a few other things I would suggest;

Use more descriptive names for variables - this usually makes it easy for you (and others) to keep track of what is going on. This usually also helps you spot issues.

search = 'up_rb'
for node in selection:
    ...

Try to avoid using specific values in a script tx == 0.002, instead you can use a “tolerance”.

# Tolerance is usually given as a function argument
# tolerance = 0.002

tx = mc.getAttr(node + '.translateX')

# Check if the absolute tx value (negative becomes positive and positive stays positive)
if abs(tx) < tolerance:
    replace = 'mid_up_rb'

# If we get here then we _know_ that it can't have been the middle - so we just check for left or right.
elif tx < 0:
    replace = 'r_up_rb'
else:
    replace = 'l_up_rb'

Avoid using select and mel eval in loops where possible, it can be expensive, and usually unnecessary.

new_name = node.replace(search, replace)
if new_name != node:
    mc.rename(node, new_name)
2 Likes

Hi! Thank you very much for the help. It works better now, but it’s working just for one follicle in the selection. It’s like in the list was just selecting the first one. And if I do this:

tx = mc.getAttr(selection[node] + ‘.translateX’)

I get an error:

Error: TypeError: file line 8: list indices must be integers, not unicode

No problem.

So the for loop you are doing;
for node in selection:
is actually looping the selection list, meaning it’s assigning the variable node to the next item in the array.
This means you want to use this instead;
tx = mc.getAttr(node + '.translateX')
as node is the name of the object :slight_smile:

1 Like

I did but it works in one

image

Could you post the full script you’re using?
It would probably help us see if there is something else causing the issue.

I change what I did before so now it’s more what you sugested me:

selection = mc.ls(sl=True) 

search = ‘up_rb’
for node in selection:
# Tolerance is usually given as a function argument
tolerance = 0.002

tx = mc.getAttr(node + '.translateX')

# Check if the absolute tx value (negative becomes positive and positive stays positive)
if abs(tx) < tolerance:
    replace = 'mid_up_rb'

# If we get here then we _know_ that it can't have been the middle - so we just check for left or right.
elif tx < 0:
    replace = 'r_up_rb'
else:
    replace = 'l_up_rb'

new_name = node.replace(search, replace)
if new_name != node:
mc.rename(node, new_name)

Besides the formatting, I’m assuming everything should be ok with that.
Out of interest, what are the translateX values of objects?
If you add some print statements in the script, it will probably help you figure out what is going wrong :slight_smile:

Thank you!! Well the truth is that part is going to be inside of of code which is creating the follicle’s base on a surface. This is for a ribbon, and the number of follicles is based on the cvs on a curve. The idea is to rename the follicles so the joints which are going to be created after, it will going to have the same name as the follicles but with the suffix jnt.

This is the code where I want to rename the follicles:

############################################################################

fols = []
fols_tr = []
bind_jnts = []
bnd_joints_rad = (length / 60) / (float(num_of_jnts)/40)

for x in range(num_of_jnts):

    fol = mc.createNode("follicle")
    mc.setAttr(fol + ".visibility", 0)
    temp_fol = mc.listRelatives(fol, p=True)[0]
    
        
    fols_tr.append(mc.rename(temp_fol, "{}follicle_{:02d}".format(prefix, x+1)))
    fols.append(mc.listRelatives(fols_tr[-1], s=True)[0])
    
    

    # connect follicle shapes to their transforms   
    mc.connectAttr(fols[-1] + ".outTranslate", fols_tr[-1] + ".translate", f=True)
    mc.connectAttr(fols[-1] + ".outRotate", fols_tr[-1] + ".rotate", f=True)

    # attach follicle shapes to the surface
    mc.connectAttr(surf + ".worldMatrix[0]", fols[-1] + ".inputWorldMatrix")
    mc.connectAttr(surf + ".local", fols[-1] + ".inputSurface")

    mc.setAttr(fols[-1] + parameter, param_joints[x])
    mc.setAttr(fols[-1] + other_param, 0.5)

    mc.parent(fols_tr[-1], follicles_grp)


    # first try to rename the follicles
    fols_tr = []

    selec = mc.ls(sl=True)
    for obj in selec:
        tx = mc.getAttr( obj + '.translateX')
        if tx < 0:
            mc.select(obj, r = True)
            mel.eval('searchReplaceNames "up_rb" "r_up_rb" "hierarchy" ')
            selec = mc.ls(sl=True)
            fols_tr.append(selec)
        elif tx < 0.02:  
            mc.select(obj, r = True)
            mel.eval('searchReplaceNames "up_rb" "mid_up_rb" "hierarchy" ')
            selec = mc.ls(sl=True)
            fols_tr.append(selec)                   
        else:
            mc.select(obj, r = True)
            mel.eval('searchReplaceNames "up_rb"  "l_up_rb" "hierarchy" ')
            selec = mc.ls(sl=True)
            fols_tr.append(selec)


        

    # create final bind joints on the surface
    bind_jnts.append(mc.createNode("joint", n="{}{:d}_jnt".format(prefix, x+1)))

    mc.parent(bind_jnts[-1], fols_tr[-1], r=True)
    mc.setAttr(bind_jnts[-1] + ".radius", bnd_joints_rad)
    mc.parent(fols_tr[-1], follicles_grp)

In all honesty, you’ve got alot going on there written in a way that will make it more difficult for you to understand/follow.
My first suggestion is to break down what is going on and rewrite it slightly to make it easier to read. Doing this frequently will absolutely help you learn scripting - its still one of the best learning techniques I use everyday.

fol = mc.createNode("follicle")
mc.setAttr(fol + ".visibility", 0)
temp_fol = mc.listRelatives(fol, p=True)[0]
    
fols_tr.append(mc.rename(temp_fol, "{}follicle_{:02d}".format(prefix, x+1)))
fols.append(mc.listRelatives(fols_tr[-1], s=True)[0])

Here, you’re creating a follicle, hiding it, getting its transform, renaming it (adding the new name to a list) and finally renaming the follicle (and adding that to another list).

The rest of the script is then referring to the last item in the list, which will just make it more confusing for you to read.

try this instead;

follicle = mc.createNode("follicle")
fols.append(follicle)

follicle_transform = mc.listRelatives(follicle, parent=True)[0]
follicle_transform = mc.rename(follicle, "{}follicle_{:02d}".format(prefix, x + 1))
fols_tr.append(follicle_transform)

mc.setAttr(follicle + ".visibility", 0)

With this, you can now refer to the renamed follicle parent as follicle_transform instead of fols_tr[-1].

For your renaming part, I see you’re dumping the list of follicle names you have and then relying on selections. This can be ok to start with but will soon drive you mad.
Instead, just rename them in the same loop.

...
mc.parent(follicle_transform, follicles_grp)

tx = mc.getAttr(follicle_transform + '.translateX')
if abs(tx) < 0.02:
    follicle_transform = mc.rename(follicle_transform, follicle_transform.replace("up_rb", "mid_up_rb"))
elif tx < 0:
    follicle_transform = mc.rename(follicle_transform, follicle_transform.replace("up_rb", "r_up_rb"))
else:
    follicle_transform = mc.rename(follicle_transform, follicle_transform.replace("up_rb", "l_up_rb"))

# create final bind joints on the surface
joint = mc.createNode("joint", n="{}{:d}_jnt".format(prefix, x + 1))
bind_jnts.append(joint)

mc.setAttr(joint + ".radius", bnd_joints_rad)
mc.parent(joint, follicle_transform, r=True)

We’re using the str.replace() method to rename the follicle with a new follicle name.
We’re also using the abs method I mentioned earlier to accept translateX values from -0.002 to 0.002 as the “middle”.

I hope this helps :slight_smile: