I'm not too proficient in Python - I'd love a little help with some code. I'm trying to select two random nodes out of all selected nodes in nuke.
I've got far enough that I can print two randomly chosen node names in the array of selected nodes, but could anyone help finish off the code so that the two nodes with the matching names are selected? Essentially I'm imagining if a node name contains chosen_nodes string, select these nodes.
Thanks.
import nuke
import random
array = []
for node in nuke.selectedNodes():
n = node['name'].value()
array.append(n)
chosen_nodes = random.sample(array, k=2)
print chosen_nodes
With this code you can select two random nodes out of several selected ones:
import nuke
import random
array = []
for node in nuke.selectedNodes():
name = node['name'].value()
array.append(name)
print(array)
if nuke.selectedNodes():
for index in nuke.selectedNodes():
index['selected'].setValue(False)
for i in range(1, 3, 1): # range(start, non-inclusive stop, step)
r = random.randint(1, len(array))
nuke.toNode(array[r-1]).setSelected(True)
array.remove(array[r-1]) # delete randomly generated element from array
array = []
Essentially I'm imagining if a node name contains chosen_nodes string, select these nodes.
This should be close to what you want!
match = 'chosen_nodes'
for node in nuke.selectedNodes():
node.setSelected(False)
if match in node['name'].value():
node.setSelected(True)
A slightly more complicated version:
def selectNodesWithFuzzyName(name, nodes=None):
"""
Set the selected nodes to only those that match the passed name.
Parameters
----------
node : str
Glob-style name of a node e.g. 'Grade*'
nodes : Optional[Iterable[nuke.Node]]
If provided, only operate on only these nodes. Otherwise
the currently selected nodes will be used.
"""
import fnmatch
if nodes is None:
nodes = nuke.selectedNodes()
for node in nodes:
node.setSelected(False)
if fnmatch.fnmatch(node['name'].value(), name):
node.setSelected(True)
selectNodesWithFuzzyName('Grade*')
Related
from link import Link
from node import Node
from path import Path
from od import OD
import sys
import traceback
import utils
class BadNetworkOperationException(Exception):
"""
You can raise this exception if you try a network action which is invalid
(e.g., trying to find a topological order on a network with cycles.)
"""
pass
class Network:
"""
This is the class used for transportation networks. It uses the following
dictionaries to store the network; the keys are IDs for the network elements,
and the values are objects of the relevant type:
node -- network nodes; see node.py for description of this class
link -- network links; see link.py for description of this class
ODpair -- origin-destination pairs; see od.py
path -- network paths; see path.py. Paths are NOT automatically generated
when the network is initialized (you probably wouldn't want this,
the number of paths is exponential in network size.)
The network topology is expressed both in links (through the tail and head
nodes) and in nodes (forwardStar and reverseStar are Node attributes storing
the IDs of entering and leaving links in a list).
numNodes, numLinks, numZones -- self-explanatory
firstThroughNode -- in the TNTP data format, transiting through nodes with
low IDs can be prohibited (typically for centroids; you
may not want vehicles to use these as "shortcuts").
When implementing shortest path or other routefinding,
you should prevent trips from using nodes with lower
IDs than firstThroughNode, unless it is the destination.
"""
def init(self, networkFile="", demandFile=""):
"""
Class initializer; if both a network file and demand file are specified,
will read these files to fill the network data structure.
"""
self.numNodes = 0
self.numLinks = 0
self.numZones = 0
self.firstThroughNode = 0
self.node = dict()
self.link = dict()
self.ODpair = dict()
self.path = dict()
if len(networkFile) > 0 and len(demandFile) > 0:
self.readFromFiles(networkFile, demandFile)
def findLeastEnteringLinks(self):
"""
This method should return the ID of the node with the least number
of links entering the node. Ties can be broken arbitrarily.
"""
# *** YOUR CODE HERE ***
# Replace the following statement with your code.
# raise utils.NotYetAttemptedException
minvalue = 1000
for i in self.node:
if (minvalue > len(self.node[i].reverseStar)):
minvalue = len(self.node[i].reverseStar)
idnode= i
return idnode
def formAdjacencyMatrix(self):
"""
This method should produce an adjacency matrix, with rows and columns
corresponding to each node, and entries of 1 if there is a link connecting
the row node to the column node, and 0 otherwise. This matrix should
be stored in self.adjacencyMatrix, which is a dictionary of dictionaries:
the first key is the "row" (tail) node, and the second key is the "column"
(head) node.
"""
self.adjacencyMatrix = dict()
for i in self.node:
self.adjacencyMatrix[i] = dict()
# *** YOUR CODE HERE ***
# Replace the following statement with your code.
# raise utils.NotYetAttemptedException
for i in self.node:
for j in self.node:
self.adjacencyMatrix[i][j]=0
for ij in self.link:
self.adjacencyMatrix[self.link[ij].tail][self.link[ij].head]=1
return self.adjacencyMatrix
def findTopologicalOrder(self):
"""
This method should find a topological order for the network, storing
the order in the 'order' attribute of the nodes, i.e.:
self.node[5].order
should store the topological label for node 5.
The topological order is generally not unique, this method can return any
valid order. The nodes should be labeled 1, 2, 3, ... up through numNodes.
If the network has cycles, a topological order does not exist. The presence
of cycles can be detected in the algorithm for finding a topological order,
and you should raise an exception if this is detected.
"""
# *** YOUR CODE HERE ***
# Replace the following statement with your code.
# raise utils.NotYetAttemptedException
for i in self.node:
self.node[i].order = []
node_list= list()
for i in self.node:
if len(self.node[i].reverseStar) == 0:
node_list.append(i)
break
if len(node_list)== 0:
raise BadNetworkOperationException()
while (len(node_list)!=self.numNodes):
for i in [x for x in self.node if x not in node_list]:
incoming_nodes = [int(j[1]) for j in self.node[i].reverseStar if j not in node_list]
if (len(incoming_nodes)== 0):
node_list.append(i)
break
for k in range(len(node_list)):
self.node[node_list[k]].order = k+1
return self.node[i].order
I can search thru a tree and get shortest path between nodes using just simple:
nx.shortest_path(G, source=, target=)
But how can I choose a path going thru a node with particular attribute's value?
I have simple graph with nodes
G = nx.Graph()
for token in document:
G.add_node(token.orth_, item = token.i, tag = token.tag_, dep = token.dep_)
and edges:
for token in document:
for child in token.children:
G.add_edge(token.orth_, child.orth_, pitem = token.i, citem = child.i,
ptag = token.tag_, pdep = token.dep_, ctag = child.tag_, cdep = child.dep_)
Can I find simple solution because now i'm struggling to build complicated function.
EDIT
The idea is to have a function like this: (sketchy)
def getPathByNode(betw_word, betw_attr, src_word, src_attr, trg_word, trg_attr):
nx.shortest_path(G, source=src, source_attr=src_attr, target=trg, target_attr=trg_attr, through=betw_word, through_attr=betw_attr)
....
But of course not all parameters must be passed.
As inputs I'd take for example:
source_attr = {'dep_': 'ROOT'}
target_attr = {'tag_': 'NN'}
through = "of" or through = "from" or through_attr = {'tag_': 'IN'}
And et cetera. I'm currently trying to build recursion starting from the middle (through='from') and searchning for neighhbors but the same situatuion - missing attributes.
for i in G.neighbors("from"):
print(i)
i is just a string.
A simple solution would be computing all paths from source to target. Then just filter out all paths without a node that has the desired condition, and choose the shortest path among this set of paths. Assuming you have an undirected and unweighted graph, something like this should work:
import networkx as nx
# Generate a sample graph:
G = nx.barabasi_albert_graph(10, 3, seed=42)
print(G.edges())
def check_attribute(G, node):
# Say the condition is node id is 3:
return node == 3
valid_paths = []
for path in nx.all_simple_paths(G, source=0, target=7):
cond = False
for node in path:
if check_attribute(G, node):
cond = True
valid_paths.append(path)
break
lengths = [len(path) for path in valid_paths]
shortest_path = valid_paths[lengths.index(min(lengths))]
print('valid paths: {}'.format(valid_paths))
print('shortest_path: {}'.format(shortest_path))
I have an interesting python "network" challenge. Not sure what data construct to use and am hoping to learn something new from the experts!
The following is a snippet from an ordered table (see SORT column) with a FROM NODE and TO NODE. This table represents a hydrologic network (watershed sequencing) from upstream to downstream. TO NODE = 0 indicates the bottom of the network.
Given there can be many branches, how does one traverse a network from any given FROM NODE to TO NODE = 0 and store the list of nodes that are sequenced over?
For example, starting at:
HYBAS_ID (this is same as FROM NODE)= 2120523430
see <---- about 2/3rd way down, the sequence of Nodes would include the following:
[2120523430, 2120523020, 2120523290, 2120523280,2120523270,2120020790, 0]
Table:
SORT FROM NODE TO NODE
30534 2121173490 2120522070
30533 2120521930 2120521630
30532 2120522070 2120521630
30531 2120521620 2120522930
30530 2120521630 2120522930
30529 2121172200 2121173080
30528 2120522930 2120523360
30527 2120522940 2120523360
30526 2120519380 2120523170
30525 2120519520 2120523170
30524 2120523440 2120523350
30523 2120523360 2120523350
30522 2120525750 2120523430
30521 2120525490 2120523430
30520 2121173080 2120522820
30519 2120523430 2120523020 <------- if you start network here
30518 2120523350 2120523020
30517 2120522820 2120523290
30516 2120523020 2120523290 <------ the second node is here
30515 2120523170 2120523280
30514 2120523290 2120523280 <------ third node here
30513 2120523160 2120523270
30512 2120523280 2120523270 <------ fourth
30511 2120523150 2120020790
30510 2120523270 2120020790 <------ fifth
30509 2120020790 0 <------ End.
Would a dictionary and some kind of graph structure work to traverse this network? The code may be fed a list of thousands or millions of FROM NODES to calculate the routing so efficiency is important.
The standard way to do this is with an unordered dictionary representing a directed graph, and then to iterate through it. First you have to populate the dictionary (which let's say is a csv for the sake of argument), and then iterate through the values. so
my_graph = {}
with open("myfile.csv") as f:
for l in f:
split_lines = l.split(",")
my_graph[int(split_lines[1])] = int(split_lines[2])
HYBAS_ID = 2120523430
current_hybas = my_graph[HYBAS_ID]
return_value = [HYBAS_ID]
while current_hybas != 0:
return_value.append(current_hybas)
current_hybas = my_graph[current_hybas]
print return_value
Should approximately get you what you want.
I'm working with Python 3.6.2 and numpy.
I'm writing code to visualize a finite element model and results.
The visualization code requires the finite element mesh nodes and elements to be identified by indices (starting a zero, no gaps) but the input models are based on ID's and can have very large gaps in the ID space.
So I'm processing all of the nodes and elements and changing them to use indices instead of ID's.
The nodes are
First step is to process the array of nodes and node coordinates. This comes to me sorted so I don't specifically have to do anything with the coordinates - I just use the indices of the nodal coordinate array. But I do need to then redefine the connectivity of the elements to be index base instead of ID based.
To do this, I create a dictionary by iterating over the array of node ids and adding each node to the dictionary using it's ID as the key and its index as the value
In the following code fragment,
model.nodes is a dictionary containing all of the Node objects, keyed by their id
nodeCoords is a pre-allocated numpy array where I store the nodal coordinates for later use in visualization. It's the indices of this array that I need to use later to redefine my elements
nodeIdIndexMap is a dictionary that I populate using the Node ID as the key and the index of nodeCoords as the value
Code:
nodeindex=0
node_id_index_map={}
for nid, node in sorted(model.nodes.items()):
nodeCoords[nodeIndex] = node.xyz
nodeIdIndexMap[nid] = nodeIndex
nodeIndex+=1
Then I iterate over all of the elements, looking up each element node ID in the dictionary, getting the index and replacing the ID with the index.
In the following code fragment,
tet4Elements is a dictionary containing all elements of type tet4, keyed using the element id
n1, n2, n3 and n4 are pre-allocated numpy arrays that hold the element nodes
element.nodes[n].nid gets the element node ID
n1[tet4Index] = nodeIdIndexMap[element.nodes[0].nid looks up the element node ID in the dictionary created in the previous fragment, returns the corresponding index and stores it in the numpy array
Code:
tet4Index = 0
for eid, element in tet4Elements.items():
id[tet4Index] = eid
n1[tet4Index] = nodeIdIndexMap[element.nodes[0].nid]
n2[tet4Index] = nodeIdIndexMap[element.nodes[1].nid]
n3[tet4Index] = nodeIdIndexMap[element.nodes[2].nid]
n4[tet4Index] = nodeIdIndexMap[element.nodes[3].nid]
tet4Index+=1
The above works, but it's slow......It takes about 16 seconds to process 6,500,000 tet4 elements (each tet4 element has four nodes, each node ID has to be looked up in the dictionary, so that's 26 million dictionary lookups in a dictionary with 1,600,000 entries.
So the question is how to do this faster? At some point I'll move to C++ but for now I'm looking to improve performance in Python.
I'll be grateful for any ideas to improve performance.
Thanks,
Doug
With the numbers you are quoting and reasonable hardware (8GB ram) the mapping can be done in less than a second. The bad news is that getting the data out of the original dicts of objects takes 60 x longer at least with the mock objects I created.
# extract 29.2821946144104 map 0.4702422618865967
But maybe you can find some way of bulk querying your nodes and tets?
Code:
import numpy as np
from time import time
def mock_data(nn, nt, idf):
nid = np.cumsum(np.random.randint(1, 2*idf, (nn,)))
nodes = np.random.random((nn, 3))
import collections
node = collections.namedtuple('node', 'nid xyz')
tet4 = collections.namedtuple('tet4', 'nodes')
nodes = dict(zip(nid, map(node, nid, nodes)))
eid = np.cumsum(np.random.randint(1, 2*idf, (nt,)))
tet4s = nid[np.random.randint(0, nn, (nt, 4))]
tet4s = dict(zip(eid, map(tet4, map(lambda t: [nodes[ti] for ti in t], tet4s))))
return nodes, tet4s
def f_extract(nodes, tet4s, limit=15*10**7):
nid = np.array(list(nodes.keys()))
from operator import attrgetter
ncoords = np.array(list(map(attrgetter('xyz'), nodes.values())))
tid = np.array(list(tet4s.keys()))
tnodes = np.array([[n.nid for n in v.nodes] for v in tet4s.values()])
return nid, ncoords, tid, tnodes, limit
def f_lookup(nid, ncoords, tid, tnodes, limit):
nmx = nid.max()
if nmx < limit:
nlookup = np.empty((nmx+1,), dtype=np.uint32)
nlookup[nid] = np.arange(len(nid), dtype=np.uint32)
tnodes = nlookup[tnodes]
del nlookup
else:
nidx = np.argsort(nid)
nid = nid[nidx]
ncoords = ncoords[nidx]
tnodes = nid.searchsorted(tnodes)
tmx = tid.max()
if tmx < limit:
tlookup = np.empty((tmx+1,), dtype=np.uint32)
tlookup[tid] = np.arange(len(tid), dtype=np.uint32)
else:
tidx = np.argsort(tid)
tid = tid[tidx]
tnodes = tnodes[tidx]
return nid, ncoords, tid, tnodes
data = mock_data(1_600_000, 6_500_000, 16)
t0 = time()
data = f_extract(*data)
t1 = time()
f_lookup(*data)
t2 = time()
print('extract', t1-t0, 'map', t2-t1)
I'm not quite sure where the problem is in this script. What I've done is this....
I have a scene with 2 curves. Each curve has three spheres linked to it.
I select the curves and run the script. It craps out and says I've got objects with matching names?
import maya.cmds as cmds
selection = cmds.ls(selection=True, type='dagNode')
# groups of ![enter image description here][1]nodes to be exported out
nodeBundles = []
for n in selection:
# list the children nodes
children = cmds.listRelatives(n, allDescendents=True, noIntermediate=True, fullPath=True, type="dagNode", path=True)
# list the transform nodes to each child node
childrenTransforms = maya.cmds.listRelatives(children, type='transform', parent=True)
# append each set of children to a unique array and then append to main array
nodeBundles.append(childrenTransforms)
# select the transform nodes
# cmds.select(childrenTransforms)
# MXS cache out each bundle of nodes
for n in nodeBundles:
cmds.select(clear=True)
cmds.xform(n, absolute=True, t=[0,0,10])
print n
FIXED CODE:
import maya.cmds as cmds
selection = cmds.ls(selection=True, type='dagNode')
# groups of ![enter image description here][1]nodes to be exported out
nodeBundles = []
for n in selection:
# list the children nodes
children = cmds.listRelatives(n, allDescendents=True, noIntermediate=True, fullPath=True, type="dagNode", path=True)
# list the transform nodes to each child node
# childrenTransforms = maya.cmds.listRelatives(children, type='transform', parent=True)
childrenTransforms = maya.cmds.listRelatives(children, type='transform', parent=True, fullPath=True)
# append each set of children to a unique array and then append to main array
nodeBundles.append(childrenTransforms)
# select the transform nodes
# cmds.select(childrenTransforms)
# MXS cache out each bundle of nodes
for n in nodeBundles:
cmds.select(clear=True)
cmds.xform(n, r=True, t=[0,0,10])
print n
By adding a list inside of a list I can then iterated based on groups of children. is this the correct method of doing so then?
nodes = []
for item in cmds.ls(sl=True, type = 'transform'):
descendants = cmds.listRelatives(ad=True, ni=True, f=True) or []
# nodes += descendants # append the list, not insert it
nodes.append(descendants)
val = 1
for grp in nodes:
for n in grp:
cmds.select(clear=True)
offset = val * 10
print offset
cmds.xform(n, r=True, t=[0,0,offset])
val += 1
Without seeing your scene or error message, my assumption is you have multiple nodes of the same name. Because Maya uses strings, it can't tell the difference between pSphere1 and... pSphere1
From the documentation on listRelatives, use the argument fullPath:
Return full pathnames instead of object names.
Like this:
childrenTransforms = maya.cmds.listRelatives(children, type='transform', parent=True, fullPath=True)
Assuming the error was in the last cmds.xform, this should make those transforms unambiguous (i.e. |group1|pSphere1)
listRelatives will work on selected objects if nothing is specified, so you can get the subnodes (with full paths) like this:
descendants = cmds.listRelatives(ad=True, ni=True, f=True) # f=True = long paths
If you were trying to use 'dagNode' to filter between shapes and geometry, it wont' work: dagNode will return both transforms and shapes. You can use 'geometryShape' to get only shapes:
descendant_shapes = cmds.listRelatives(ad=True, ni = True, f=True)
but in your case that would return the curveShape as well. You could filter out the curve with:
descendants = cmds.ls(descendants, type= surfaceShape, l=True) # l=True keeps long paths
Also: in you code you are passing lists-of-lists into nodeBundles, which Maya won't like. You should flatten the list by adding items one at a time:
nodes = []
for item in cmds.ls(sl=True, type = 'transform'):
descendants = cmds.listRelatives(ad=True, ni=True, f=True) or []
nodes += descendants # append the list, not insert it
for n in nodes:
cmds.select(clear=True)
cmds.xform(n, r=True, t=[0,0,10])