Jump to content

Compare difference between two networks


spev

Recommended Posts

If you're comfortable with Python, the first thing that comes to mind for me is creating sets out of lists of the nodes in the networks and using the set boolean operations to compare them. The basic logic would be:

if network_a.issuperset(network_:
    net_diff = network_a.difference(network_
elif network_b.issuperset(network_a):
    net_diff = network_b.difference(network_a)
else:
    net_diff_a = network_a.difference(network_
    net_diff_b = network_b.difference(network_a)
    

Where network_a and network_b are the sets of node names. I'll see if I can cook up something a bit more substantial for you later on. 

  • Like 1
Link to comment
Share on other sites

Wrote up a little script, create a custom shelf tool and paste this in the Script tab to use it:


# Houdini Python shelf tool for comparing node networks
# Usage: Select first network, shift-select second network, launch tool

def node_names(networks):
    node_lists = ()
    for network in networks:
        nodes = network.glob('*')
        node_lists += (set([node.name() for node in nodes]),)
    return node_lists

def print_added_or_removed_nodes(a_or_r):
    if a_or_r == 'added':
        nodes = list(network_b.difference(network_a))
        message = "Nodes added to {}: \n".format(net_b_name)
    else:
        nodes = list(network_a.difference(network_)
        message = "Nodes removed in {}: \n".format(net_b_name)
        
    if nodes != []:
       nodes.sort()
    
    for node in nodes:
        message += node + '\n'
    return message
    
def print_added_and_removed_nodes():
    message = print_added_or_removed_nodes(a) + '\n' + \
              print_added_or_removed_nodes(r)
    return message    

networks = hou.selectedNodes()
net_b_name = networks[1].name()
network_a, network_b = node_names(networks)

nodes_added = network_b.issuperset(network_a)
nodes_removed = network_a.issuperset(network_

a = 'added'
r = 'removed'

if nodes_added:
    hou.ui.displayMessage(print_added_or_removed_nodes(a))
elif nodes_removed:
    hou.ui.displayMessage(print_added_or_removed_nodes(r))
else:
    hou.ui.displayMessage(print_added_and_removed_nodes())
      

Let me know if this works out for you.   :)

Edited by jrockstad
  • Like 2
Link to comment
Share on other sites

That's a nice script, but it doesn't tell you if things like parameters on nodes have changed. Using the "as code" method looks at everything in the networks. Using a list of nodes could work depending on the needs of the workflow.

 

Ah, yeah, looking back at the original post it's not perfectly clear if he's referring to differences in the overall node network, on parameters, or both. It seems like my current script could be a good jumping off point in any case, since it already has the ability to filter the list of nodes to check based on if they're shared between both networks. I definitely had fun writing that script so I'll see if I can tweak it a bit. 

  • Like 1
Link to comment
Share on other sites

Guys... Amazing answers.. Thank you both very much... I was hoping to find out the following .. Extra nodes, parameter changes and possibly dependencies too... Basically as much info as poss...

Thanks again I will try both options

Link to comment
Share on other sites

Modified version of my script, now including parameter changes:


# Houdini Python shelf tool for comparing node networks
# Prints changes in networks followed by changes in parameters

# Usage: Select first network, shift-select second network, launch tool

# Network comparison functions

def get_node_names(networks):
    node_lists = ()
    
    for network in networks:
        nodes = network.children()
        node_lists += (set([node.name() for node in nodes]),)
        
    return node_lists

def print_added_or_removed_nodes(a_or_r):
    if a_or_r == 'added':
        nodes = list(network_b.difference(network_a))
        message = "Nodes added to '{}': \n\n".format(net_b_name)
    else:
        nodes = list(network_a.difference(network_)
        message = "Nodes removed in '{}': \n\n".format(net_b_name)
        
    if nodes != []:
       nodes.sort()
    
    for node in nodes:
        message += "    " + node + '\n'
        
    return message
    
def print_added_and_removed_nodes():
    message = print_added_or_removed_nodes(a) + '\n' + \
              print_added_or_removed_nodes(r)
              
    return message

# Parameter comparison functions

def get_parms(networks, shared_nodes):
    parm_dicts = ()
    
    for network in networks:
        node_parms = {}
        nodes = network.children()
        for node in nodes:
            if node.name() in shared_nodes:
                parm_tuple = [(node.name(), node.parmTuples())]
                node_parms.update(parm_tuple)
        parm_dicts += (node_parms,)
                
    return parm_dicts
    
def compare_parms(parm_dicts, shared_nodes):
    message = ""
    a_parms, b_parms = parm_dicts
    
    for node in shared_nodes:
        a_parm_vals = []
        b_parm_vals = []
        parm_labels = []
        
        for parm_tuple in a_parms[node]:
            for parm in parm_tuple:
                a_parm_vals.append(parm.evalAsString())
                parm_labels.append(parm.name())
        for parm_tuple in b_parms[node]:
            for parm in parm_tuple:
                b_parm_vals.append(parm.evalAsString())
        
        if a_parm_vals != b_parm_vals:
            message += "Changed parameters in node {}:".format(node) + '\n\n'
            for val in range(0, len(parm_labels) - 1):
                if a_parm_vals[val] != b_parm_vals[val]:
                    message += "    Value in '{}' for '{}': {}".format \
                               (net_a_name, parm_labels[val], a_parm_vals[val]) + \
                               '\n' + \
                               "    Value in '{}' for '{}': {}".format \
                               (net_b_name, parm_labels[val], b_parm_vals[val]) + \
                               '\n\n'
                
    return message
    
# Script start

networks = hou.selectedNodes()
net_a_name = networks[0].name()
net_b_name = networks[1].name()
network_a, network_b = get_node_names(networks)

nodes_added = network_b.issuperset(network_a)
nodes_removed = network_a.issuperset(network_
shared_nodes = list(network_a.intersection(network_)

parm_dicts = get_parms(networks, shared_nodes)

a = 'added'
r = 'removed'

if nodes_added:
    hou.ui.displayMessage(print_added_or_removed_nodes(a))
elif nodes_removed:
    hou.ui.displayMessage(print_added_or_removed_nodes(r))
else:
    hou.ui.displayMessage(print_added_and_removed_nodes())
    
hou.ui.displayMessage(compare_parms(parm_dicts, shared_nodes)) 
   

There's definitely a lot of room to polish it up, and in particular I would like to add:

 

- Option for user to choose whether they want to see node changes, parameter changes, or both

- Option to print output to file 

- More efficient / readable output, especially for parameters

 

...but for now, it does exactly what it says on the tin.  :)

  • Like 4
  • Thanks 1
Link to comment
Share on other sites

  • 3 years later...

@jrockstad

Hi I tried to use the code as is its throwing syntax errors

Quote

 

SyntaxError: ('invalid syntax', ('tool_6', 23, 15, '        message = "Nodes removed in \'{}\': \\n\\n".format(net_b_name)\n'))


 

 

I tried fixing it but got another syntax error....

(network_) to (network_b))

 

Quote

SyntaxError: ('invalid syntax', ('tool_6', 94, 12, 'shared_nodes = list(network_a.intersection(network_)\n'))

I tried fixing the second error

nodes_removed = network_a.issuperset(network_
shared_nodes = list(network_a.intersection(network_)

to...

nodes_removed = network_a.issuperset(network_b)
shared_nodes = list(network_a.intersection(network_b))

Now the code runs but shows empty message window...

Can you have a another look at this code...It will be very useful...

Thanks,

Rama.

Link to comment
Share on other sites

  • 6 months later...

Many thanks @jrockstad. Fixed some minor issues to make it work for h18+. For convenience I also created a gist here.

# Houdini Python shelf tool for comparing node networks
# Prints changes in networks followed by changes in parameters
# Original Author: @jrockstad
# https://forums.odforce.net/topic/24410-compare-difference-between-two-networks/

# Usage: Select first network, shift-select second network, launch tool

# -----------------------------------------------
#   Network comparison functions
# -----------------------------------------------

def get_node_names(networks):
    node_lists = ()
    
    for network in networks:
        nodes = network.children()
        node_lists += (set([node.name() for node in nodes]),)
        
    return node_lists

def print_added_or_removed_nodes(a_or_r):
    message = ''

    if a_or_r == 'added':
        nodes = list(network_b.difference(network_a))
        message = "Nodes added to '{}': \n\n".format(net_b_name)
    else:
        nodes = list(network_a.difference(network_b))
        message = "Nodes removed in '{}': \n\n".format(net_b_name)
        
    if nodes != []:
       nodes.sort()
    
    for node in nodes:
        message += "   {}".format(node)

    return message
    
def print_added_and_removed_nodes():
    message = print_added_or_removed_nodes(a) + '\n' + \
              print_added_or_removed_nodes(r)
              
    return message

# -----------------------------------------------
#   Parameter comparison functions
# -----------------------------------------------

def get_parms(networks, shared_nodes):
    parm_dicts = ()
    
    for network in networks:
        node_parms = {}
        nodes = network.children()
        for node in nodes:
            if node.name() in shared_nodes:
                parm_tuple = [(node.name(), node.parmTuples())]
                node_parms.update(parm_tuple)
        parm_dicts += (node_parms,)
                
    return parm_dicts
    
def compare_parms(parm_dicts, shared_nodes):
    message = ''
    a_parms, b_parms = parm_dicts
    
    for node in shared_nodes:
        a_parm_vals = []
        b_parm_vals = []
        parm_labels = []
        
        for parm_tuple in a_parms[node]:
            for parm in parm_tuple:
                a_parm_vals.append(parm.evalAsString())
                parm_labels.append(parm.name())
        for parm_tuple in b_parms[node]:
            for parm in parm_tuple:
                b_parm_vals.append(parm.evalAsString())
        
        if a_parm_vals != b_parm_vals:
            message += "Changed parameters in node {}:".format(node) + '\n\n'
            for val in range(0, len(parm_labels) - 1):
                if a_parm_vals[val] != b_parm_vals[val]:
                    message += "    Value in '{}' for '{}': {}".format \
                               (net_a_name, parm_labels[val], a_parm_vals[val]) + \
                               '\n' + \
                               "    Value in '{}' for '{}': {}".format \
                               (net_b_name, parm_labels[val], b_parm_vals[val]) + \
                               '\n\n'
    return message

# -----------------------------------------------
#   Init
# -----------------------------------------------

networks = hou.selectedNodes()
net_a_name = networks[0].name()
net_b_name = networks[1].name()
network_a, network_b = get_node_names(networks)

nodes_added = network_b.issuperset(network_a)
nodes_removed = network_a.issuperset(network_b)
shared_nodes = list(network_a.intersection(network_b))

parm_dicts = get_parms(networks, shared_nodes)

a = 'added'
r = 'removed'

if nodes_added:
    hou.ui.displayMessage(print_added_or_removed_nodes(a))
elif nodes_removed:
    hou.ui.displayMessage(print_added_or_removed_nodes(r))
else:
    hou.ui.displayMessage(print_added_and_removed_nodes())
    
hou.ui.displayMessage(compare_parms(parm_dicts, shared_nodes))

 

Edited by p2or
python
  • Like 1
Link to comment
Share on other sites

  • 1 year later...

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...