0
$\begingroup$

I want to hide (turn off eyeball icon) a collection by its name.

Refer to this : How to "Hide a Collection in viewport" but not "Disable in Viewport" via script in Python

i can't use bpy.data.collections[name].hide_viewport as it will disabling rather than hiding (turn off monitor icon)

so have to use layer_collection :

collections = bpy.context.view_layer.layer_collection.children
colname = "mycollection"
for collection in collections:
    if collection.name == colname :
        collection.hide_viewport = True

That's 1 level down , if i have multi level collection, than i have to iterate recursively until i found it. it's too slow.

Is there new API or any simple method in 2.90 or 2.91 ?

Thanks

$\endgroup$
3
  • $\begingroup$ For how many collections is it too slow? $\endgroup$ – lemon Nov 21 '20 at 15:03
  • $\begingroup$ maybe not 'slow' in term of duration, but the process is so inefficient. To swith a single collection, we need to cycle through all the collections available. Don't you think ? $\endgroup$ – andio Nov 23 '20 at 11:42
  • $\begingroup$ Yes, as indicated below in the answer, you need to go through all of them, anyway. That's the API as they are. Alternative could be modify the source code of the API, propose it as standard, etc. but this is another story. $\endgroup$ – lemon Nov 23 '20 at 11:49
1
$\begingroup$

I don't think there is an API for that.

But some geeky experiments, as you said this is "too slow".

First build a test case for 40000 collections: 1000 root collections each having a 3 x 3 chidren hierarchy (1000 + 3000 + 9000 + 27000).

The code to create it (runtime will be a bit long):

import bpy
import random
import time

def generate_children(parent, amount):
    new = bpy.data.collections.new
    collections = [new("test") for i in range(amount)]
    for c in collections:
        parent.children.link(c)
    return collections

def generate_hierarchy(parents, amount, depth): 
    children = parents
    for i in range(depth):
        children = [c for p in children for c in generate_children(p, amount)]

parents = generate_children(master_collection, 1000)
generate_hierarchy(parents, 3, 3)

Now, direct search (recursive) can be:

def search(parent, name):
    if parent.name == name:
        return parent
    
    for c in parent.children:
        result = search(c, name)
        if result:
            return result
    return None

And search using a map between a child name and its parent collection. The map is slower to build than a direct search but can be used several times:

def create_search_map():
    all = bpy.data.collections
    d = {c.name: p for p in all for c in p.children if p.children}
    return d

def search_on_map(d, parent, name):

    path = [name]
    while True:
        p = d.get(name)
        if p:
            name = p.name
            path.append(name)
        else:
            break
    path.reverse()
    
    result = parent
    for name in path:
        result = result.children[name]
    return result

So we can compare:

layer_master_collection = bpy.context.view_layer.layer_collection

start = time.time()
for i in range(1000):
    collection = random.choice(bpy.data.collections)
    search(layer_master_collection, collection.name)
end = time.time()
print(end-start)

start = time.time()
d = create_search_map()
for i in range(1000):
    collection = random.choice(bpy.data.collections)
    search_on_map(d, layer_master_collection, collection.name)
end = time.time()
print(end-start)

First print gives 17.58s, 17ms per call.

Second print gives 1.84s, 2ms per call (but again, use the map only if you need to search for several).

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.