4
$\begingroup$

In my startup file I have various node groups that I keep on hand for common tasks. Sometimes I will add a new node group or material that contains an existing group inside it. So what happens is SwitchNode becomes SwitchNode.001, which not only clutters my .blend, but also makes updating difficult. If I later decide to add a new input socket to SwitchNode I have two of them to deal with.

What I am looking for is a way to find where SwitchNode.001 is being used as a dependency (in what other group or material) - so that I can select SwitchNode from the group's drop-down selector instead. Effectively consolidating the .blend so there is only one true SwitchNode... and first I want to examine how SwitchNode.001 is being used, in order to make sure I don't break any functionality when I update my node groups.

One might guess the Outliner would provide such functionality to quickly inspect the dependency hierarchy of whatever datablock you search for. But when I navigate to Blender File > Node Groups > SwitchNode.001 and R-click then View > Show Hierarchy, the Outliner does not show me that datablock's hierarchy, but instead collapses the entire hierarchy so that I need to scroll back up to the top of the Outliner and start over.

How can I view which materials or node groups are relying on a given node group?

Edit: I'm adding the Python tag just in case the only way to do this is with Python. We can remove it later if Python turns out not to be necessary.

$\endgroup$

1 Answer 1

2
$\begingroup$

enter image description here

The script below lists all node groups and their users as a tree inside the console. Each user displays the node group’s occurrences and its name(s) inside the user (so you can do a ctrl+f for the group). The node groups are also sorted by the number of links/connections so you can find possibly redundant/duplicated node groups.

You will need to have the system console open for Blender, as the output is displayed here. Run the script from within Blender's Text Editor.

from os import system
import os.path
import pkg_resources
import platform
import sys

import bpy
from rich.padding import Padding
from rich.panel import Panel
from rich import print
from rich.rule import Rule
from rich.tree import Tree


def get_values(items_tuple):
    for items in items_tuple:
        try:
            for itm in items:
                if isinstance(itm, int):
                    return itm
        except TypeError:
            pass


installed = {pkg.key for pkg in pkg_resources.working_set}
missing = {'rich'} - installed

if missing:
    import pip
    pip.main(['install', 'rich', '--user'])

home_folder = os.path.expanduser("~")
user_site_packages_folder = "{}/.local/lib/python3.10/site-packages".format(
  home_folder)
if user_site_packages_folder not in sys.path:
    sys.path.append(user_site_packages_folder)

if platform.system() == "Windows":
    system("cls")
elif platform.system() == "Darwin":
    system("printf '\\33c\\e[3J'")
elif platform.system() == "Linux":
    system("clear")

ng_users_dict = bpy.data.user_map(subset=bpy.data.node_groups)

node_group_users = {
  key: list(value)
  for key, value in bpy.data.user_map(subset=bpy.data.node_groups).items()
  if not isinstance(key, bpy.types.GeometryNodeTree)
}

[
  node_group_users[key].append(len(key.links))
  for key, _value in node_group_users.items()
]
sorted_node_group_users = {
  key: value
  for key, value in sorted(node_group_users.items(), key=get_values)
}

for node_group, users in sorted_node_group_users.items():
    print(Rule(style="grey50"))
    print(
      Panel(node_group.name + "\n[grey50]%s links" % len(node_group.links),
            border_style="dim green",
            width=20))
    panels = []
    count = 0
    for count, usr in enumerate(users):
        if isinstance(usr, bpy.types.Material):
            group_names = [
              node.name for node in usr.node_tree.nodes
              if node.type == 'GROUP' and node.node_tree == node_group
            ]
            panels.append(
              Panel(
                usr.name
                + "[dim grey50]\n(%s)[/][grey50]\n" % usr.user_of_id(node_group)
                + '\n'.join(group_names),
                border_style="dim red",
                width=max(len(group_names[0]) + 4, 20)))
        elif isinstance(usr, bpy.types.NodeTree):
            group_names = [
              node.name for node in usr.nodes
              if node.type == 'GROUP' and node.node_tree == node_group
            ]
            panels.append(
              Panel(
                usr.name
                + "[dim grey50]\n(%s)[/][grey50]\n" % usr.user_of_id(node_group)
                + '\n'.join(group_names),
                border_style="dim green",
                width=max(len(group_names[0]) + 4, 20)))

    tree = Tree("[grey50]%s users:" % count, guide_style="dim grey50")
    [tree.add(pnl) for pnl in panels]
    print(Padding.indent(tree, 2))

print(Rule(style="grey50"))
$\endgroup$
6
  • 1
    $\begingroup$ Hey ! Thanks for the answer, it looks like it's an interesting tool. Would you mind adding a screenshot of the expected output for reference ? :) $\endgroup$
    – Gorgious
    Commented Nov 30, 2023 at 9:13
  • $\begingroup$ From what I see in the screenshot, this looks very useful! I haven't managed to get it set up right though. I launched Blender from the console (in macOS). Then, I pasted the line to import pip from within Blender's Python console. I got SyntaxError: incomplete input and the caret ^ points to the beginning of '--user’ (Note that I have tried changing "user" to my actual system user name - neither way works.) What am I doing wrong? Can I use Homebrew to install it instead of pip? (I'll wait for advice before I go breaking stuff...) $\endgroup$
    – Mentalist
    Commented Dec 1, 2023 at 1:32
  • $\begingroup$ @Mentalist Oops, a curly quote was in '--user’ Fixed my original comment now $\endgroup$ Commented Dec 1, 2023 at 5:22
  • $\begingroup$ Thanks for taking another look and revising. Unfortunately I've run into another issue. I get: NameError: name 'Rule' is not defined. Since 'Rule' was supposed to be defined by from rich.rule import Rule, I guess this means rich still hasn't been installed successfully. Do you have any ideas about this? $\endgroup$
    – Mentalist
    Commented Dec 4, 2023 at 0:40
  • $\begingroup$ @Mentalist The site packages directory most likely isn't added to PATH – I've updated the code now with a fix $\endgroup$ Commented Dec 4, 2023 at 4:12

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .