# Python : hide collection (turn off the eyeball icon of collection) in outliner

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

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

• For how many collections is it too slow? – lemon Nov 21 '20 at 15:03
• 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 ? – andio Nov 23 '20 at 11:42
• 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. – lemon Nov 23 '20 at 11:49

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:
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).