Connect different multiple attributes between two different nodes

i am trying to auto connect multiple attributes at once.

Right now I am creating two different lists, one for the left node and one for the right. I am listing there the attributes and then I want with a loop to connect each one attribute of left list to the coordinate attribute of right list. (Both lists have the same number of elements). Here is what I have at the moment but it pops an error in the loop:

import maya.cmds as cmds


left_LIST = {}
customAttrList = cmds.listAttr('null1',k=True,ud=True)
if customAttrList:
    for attr in customAttrList:
        left_LIST[attr] = cmds.getAttr('null1'+'.'+attr)
print left_LIST
    
    
right_LIST = cmds.aliasAttr('blendShape1', q=1)
print right_LIST

i=0

for i in range(len(left_LIST)):
    cmds.connectAttr('null1.' + left_LIST[i], 'blendshape1.'+ right_LIST[i])
1 Like

When you have an error, it’s pretty essential to post the error. Otherwise we are guessing.

But I guess the problem is that you are using cmds.aliasAttr() and that returns more than just the blendshape targets. So you’re trying to connect something wrong in the loop.

I honestly have no idea how to do this in maya.cmds. I use PyMEL to iterate over pm.PyNode('blendShape1').weight which does only return the indices. But that is derived from a Maya API function.

In Maya.cmds, the only other thing I can think off off-hand is cmds.blendShape('blendShape1', weight=True, q=1) which will list the VALUE of each weight. But at least you get the correct number of weights. And you could use that in your range iterator to get the correct number, at least.

But depending on corrective shapes, or if you delete a weight, and add another, the index order will get messed up. So this can still fail. Which is why I like the PyMEL version. It returns the proper index of each target and gives you the plug to connect to, directly.

For example, after I deleted some random targets and added new ones, I get this, out of order:

for each in pm.PyNode('blendShape1').weight:
    print(each)

# RESULT:
blendShape1.weight[0]
blendShape1.weight[2]
blendShape1.weight[3]
blendShape1.weight[4]
blendShape1.weight[6]
blendShape1.weight[7]
blendShape1.weight[8]

Alternatively, since cmds.aliasAttr('blendShape1', q=1) seems to return a list of [target, weight, target, weight, target, weight], you could also just iterate over every 2nd element in that list, and maybe you’ll get the correct result (I have no idea!):

for each in right_LIST:
    print(each)

// RESULT:
pSphere2
weight[0]
pSphere4
weight[2]
pSphere5
weight[3]
pSphere6
weight[4]
pSphere8
weight[6]
pSphere9
weight[7]
pSphere10
weight[8]

So instead, skip every 2nd one. This notation is called “index slicing” in Python.

for each in right_LIST[1::2]:
    print(each)

// RESULT:
weight[0]
weight[2]
weight[3]
weight[4]
weight[6]
weight[7]
weight[8]

And lastly (sorry for the huge long reply), you don’t need to use a range to iterate over things in Python. Iterate over them directly when possible.

And you can combine two lists together by using zip(). For example:

for eachLeft, eachRight in zip(left_LIST, right_LIST[1::2]):
   cmds.connectAttr("null1." + eachLeft, "blendshape1." + eachRight)
2 Likes

Very explanatory, thank you very much for your time.
it runs smoothly thank you very much.

1 Like

Another question,
for this example i used a null node with some custom attributes that i wanted to connect to my blendshape targets, now what about if you have attributes that contain multiple values?
I mean how can you put the multivalues in a list in order to run the above script?
i even try to loop and just set some simple values on them and i got this:
# Error: RuntimeError: file <maya console> line 2: setAttr: The attribute 'test.Outputs' is a multi. Its values must be set individually. #

Better to post your code and your errors if you want help. Not just one or the other.

Yes you are right I am sorry.
Well let me explain what i want to achieve
here in the image the left node is the null1 that has multivalue attributes, specifically i am interested on bsOutput values, these are the values that i want to connect with your above script to the blendshape targets.
So i believe that i need to put these bsOutputs multivalues in a list and then use this list to your script.
Initially i get the value of just one attr and then set a different value to it (just for testing).
then i tried to put all these i a list but when i print, the list is empty:(

import maya.cmds as cmds


Get = cmds.getAttr("null1.bsOutputs[0]")
Set = cmds.setAttr("null1.bsOutputs[0]",1)
Get = cmds.getAttr("null1.bsOutputs[0]")
print Get

1.0

left_LIST = {}
customAttrList = cmds.listAttr('null1.bsOutputs',k=True,ud=True)

if customAttrList:
    for attr in customAttrList:
        left_LIST[attr] = cmds.getAttr("null1.bsOutputs[attr]")
print left_LIST
print left_LIST
{}

The bsOutputs are 687 in total and the blendshape targets are 681
as you can see in the images they skip some connections of bsOutputs and then continue the connections.
I was thinking of running the script in three parts and puting length in the lists for example
left_List (0-95)---->right_List(0-95)
left_List (100-610)---->right_List(96-606)
left_List (613-686)---->right_List(607-680)


I only skimmed your code. But I can spot one problem:

cmds.getAttr("null1.bsOutputs[attr]")

You can’t put [attr] inside the string like that. You are literally telling Maya to look for an attribute named null1.bsOutputs[attr].

You would need something like, but not necessarily:
cmds.getAttr("null1.bsOutputs[" + attr + "]")

(But that totally depends on what attr is equal to in your code. Presumably an integer. I didn’t test your code. All I’m saying is “attr” can’t be inside the string like that. Otherwise it literally means “attr”, not the value of attr.)

To piggyback off this…PyMEL, for it’s own problems, imo excels quite well at accessing and setting attribute data, without dealing with archaic string concatenation.

1 Like

I see, forgive me for so many questions, i am trying to learn.
well even with this correction i still get an empty list

import maya.cmds as cmds

left_LIST = {}
customAttrList = cmds.listAttr('null1.bsOutputs',k=True,ud=True)

if customAttrList:
    for attr in customAttrList:
        left_LIST[attr] = cmds.getAttr("null1.bsOutputs[" + attr + "]")
print left_LIST

print left_LIST
{}

if i run just this line:

cmds.getAttr("null1.bsOutputs[" + attr + "]")
prints out:

> # Error: TypeError: file <maya console> line 1: cannot concatenate 'str' and 'int' objects #

The attr it is integer.
Again thank you for your time

cmds.getAttr('null1.bsOutputs[' + str(attr) + ']')

…

print (left_LIST)

1 Like

Thank you,
i tried this as a single line and obviously prints the error:
cmds.getAttr('null1.bsOutputs[' + str(attr) + ']')

> # Error: NameError: file <maya console> line 1: name 'attr' is not defined #

Then i run this block:

left_LIST = {}
customAttrList = cmds.listAttr('null1',k=True,ud=True)
if customAttrList:
    for attr in customAttrList:
        left_LIST[attr] = cmds.getAttr("null1.bsOutputs[" + str(attr) + "]")
print left_LIST

it doesn’t pop any error but the list is still empty.

print left_LIST
{}

I don’t quite understand what you want to achieve.
If you need to get a list with the values of the ‘bsOutputs’ attribute for the ‘embeddedNodeRL4’ node (node name ‘null1’), then the whole code is wrong.
First: it is not clear why you are using the “keyable” and “userDefined” flags in the ‘listAttr’ command?
With these flags, the ‘bsOutputs’ attribute will not be listed in the list of attributes returned by the ‘listAttr’ command.
If you need to get a list with the values of only one attribute ‘bsOutputs’ for the ‘embeddedNodeRL4’ node (node name ‘null1’), then you can use this code:

import maya.cmds as cmds

left_LIST = []

My_RL4_node = 'null1'
My_attrib = 'bsOutputs'
My_RL4_attrib = My_RL4_node + '.' + My_attrib

allAttrList = cmds.listAttr(My_RL4_node)

#print(allAttrList)
#print(cmds.getAttr(My_RL4_attrib))

if (My_attrib in allAttrList):
    left_LIST = cmds.getAttr(My_RL4_attrib)[0]

print(left_LIST)

PS: Sorry for the possible misunderstandings, English is not my first language…

1 Like

Thank you very much,
indeed this code put all the multivalues of the embeddedNodeRL4 into a list.

Then i try to connect these values with the blenshape targets using a combination of the above script and yours but i have an error again…

import maya.cmds as cmds

left_LIST = []

My_RL4_node = 'null1'
My_attrib = 'bsOutputs'
My_RL4_attrib = My_RL4_node + '.' + My_attrib

allAttrList = cmds.listAttr(My_RL4_node)

#print(allAttrList)
#print(cmds.getAttr(My_RL4_attrib))

if (My_attrib in allAttrList):
    left_LIST = cmds.getAttr(My_RL4_attrib)[0]

print(left_LIST)

right_LIST = cmds.aliasAttr('blendShape1', q=1)
print right_LIST

for each in pm.PyNode('blendShape1').weight:
    print(each)
    
for each in right_LIST:
    print(each)
    
for each in right_LIST[1::2]:
    print(each)
    
for eachLeft, eachRight in zip(left_LIST, right_LIST[1::2]):
   cmds.connectAttr( 'My_RL4_attrib' + eachLeft, "blendShape1." + eachRight)

It prints:
# Error: TypeError: file <maya console> line 2: cannot concatenate 'str' and 'float' objects #

You are english are great by the way, not my first language also.

Okay, I reread your previous posts more carefully.
You want to concatenate attributes by index.
Below I have provided a ready-made solution.
But keep in mind, if connections with the specified attributes have already been established, an error will be thrown! You need to consider checking for such cases. And decide what to do (reconnect the attributes or leave them and continue to combine the rest of the attributes).
Also keep in mind that if the number of attribute values ​​specified exceeds the number of existing values, then those values ​​will be created and added to the attribute.
Check the script in a scene where the ‘bsOutputs’ attributes of the ‘embeddedNodeRL4’ node are not connected to the ‘weights’ attributes of the ‘blendShape’ node.
Good luck!


import maya.cmds as cmds

My_RL4_node = 'null1'
My_RL4_attrib = 'bsOutputs'
My_RL4_ful_attrib = My_RL4_node + '.' + My_RL4_attrib

My_BS_node = 'blendShape1'
My_BS_attrib = 'weight'
My_BS_ful_attrib = My_BS_node + '.' + My_BS_attrib

all_RL4_AttrList = cmds.listAttr(My_RL4_node)

if (My_RL4_attrib in all_RL4_AttrList): L = cmds.getAttr(My_RL4_ful_attrib, s=True)

print(L)

all_BS_AttrList = cmds.listAttr(My_BS_node)

if (My_BS_attrib in all_BS_AttrList): R = cmds.getAttr(My_BS_ful_attrib, s=True)

print(R)

# If R==L, Left(All) to Right(All)
if R==L:
    for i in range(R):
    cmds.connectAttr(My_RL4_ful_attrib+'['+str(i)+']', My_BS_ful_attrib+'['+str(i)+']')

        #Or, as You asked earles:

# Left(0-95) to Right(0-95)
for i in range(0,95):
    cmds.connectAttr(My_RL4_ful_attrib+'['+str(i)+']', My_BS_ful_attrib+'['+str(i)+']')

# Left(100-610) to Right(96-606)
for i in range(100,610):
    cmds.connectAttr(My_RL4_ful_attrib+'['+str(i)+']', My_BS_ful_attrib+'['+str(i-4)+']')

# Left(613-686) to Right(607-680)
for i in range(613,686):
    cmds.connectAttr(My_RL4_ful_attrib+'['+str(i)+']', My_BS_ful_attrib+'['+str(i-6)+']')

The point is that you don’t need attribute values.

  1. You check that the object you specified has the attribute you specified.
  2. Then you ask for the number of values for the attribute you specified (getAttr with flag ‘s’: ‘size’ - Returns the size of a multi-attribute array. Returns 1 if non-multi).
  3. Connect attributes.
    If you know exactly what you want, and you know exactly what you are doing, then you can skip the previous part and immediately connect the attributes.

import maya.cmds as cmds

# Left(0-95) to Right(0-95)
for i in range(0,95):
    cmds.connectAttr('null1.bsOutputs['+str(i)+']', 'blendShape1.weight['+str(i)+']')

# Left(100-610) to Right(96-606)
for i in range(100,610):
    cmds.connectAttr('null1.bsOutputs['+str(i)+']', 'blendShape1.weight['+str(i-4)+']')

# Left(613-686) to Right(607-680)
for i in range(613,686):
    cmds.connectAttr('null1.bsOutputs['+str(i)+']', 'blendShape1.weight['+str(i-6)+']')
3 Likes

Oh my GOD!!
Thank you very very much.
It worked!!
I will have to study the code line by line, you are amazing, everyone here is very helpfull
and my bad i didnt explain it better previously
Thank you again