Ah yes. Node editor layout. My old nemesis
I don’t know of a good interface to the node editor. But the UI is written in Qt, so …
You can, with PySide2, get references to the QGraphicsItem objects that are the individual nodes of the NodeEditor. And from there, you can get/set their x/y positions.
Unfortunately because you are looking at the UI objects directly, you can get the node that’s drawn in the NodeEditor, but there’s no sure-fire way to tell which MObject in the Maya scene that the node corresponds to. You can read the current name displayed on the node, but there are NodeEditor options that don’t always show the full name, so it’s not reliable.
You may be able to do things using selection, but that didn’t fit my use-case (and I HATE using selection) so I didn’t do any tests with it.
The thing I wanted was a way to lay out the graph, taking where a node is plugged into another node into account. Hence all the Qt shenanigans.
Unfortunately this is all basically a hack, and is something that’s only partway through development, so there’s a LOT I don’t know, and there’s likely a lot of corner cases that I don’t handle. But this should help you get started.
from shiboken2 import wrapInstance
from maya import OpenMayaUI as mui
from PySide2.QtWidgets import (
# This is currently the best way I know of to get the
# Maya object associated with the node editor node.
# But it's unreliable
chis = node.childItems()
chis = [i for i in chis if isinstance(i, QGraphicsSimpleTextItem)]
if not chis:
nameItem = chis
panel = cmds.getPanel(scriptType="nodeEditorPanel")
name = pan + "NodeEditorEd"
ctrl = mui.MQtUtil.findControl(name)
if ctrl is None:
raise RuntimeError("Node editor is not open")
nodeEdPane = wrapInstance(ctrl, QWidget) # in py2 you will need long(ctrl)
stack = nodeEdPane.findChild(QStackedLayout)
graphView = stack.currentWidget().findChild(QGraphicsView)
scene = graphView.scene()
scene = getCurrentView()
items = [item for item in scene.items() if isinstance(i, QGraphicsItem)]
for item in item:
print(item.pos().x(), item.pos().y()) # setX and setY will set the position