Rant... Python/Rhinoscriptsyntax layer methods unreliable

I have a file that has almost 1000 layers, 165 top level layers plus sublayers. Many of the sublayers have the same name, and I want to turn off all of the sublayers that have a specific name or a certain snippet of text in the name.

This (python/rhinoscriptsyntax) totally doesn’t work:

import rhinoscriptsyntax as rs
import scriptcontext as sc
def TurnOffLayerViaNameSnippetList():
    for i in range(len(names)):
        if snippet in names[i].lower():
            rs.LayerVisible(names[i], False)
    print found_count

I get 165 as a found_count but the layers containing the text snippet in their name remain on.
I have also tried this via RhinoCommon and scriptcontext access to the layer table, same problem

The equivalent in vb Rhinoscript works perfectly.

Option Explicit
Call TurnOffLayerViaNameSnippet()
Sub TurnOffLayerViaNameSnippet()
    Dim layers, i, snippet, found_count
    snippet = "textbit"
    found_count = 0
    layers = Rhino.LayerNames
    For i=0 To Ubound(layers)
        If instr(1, lcase(layers(i)), snippet) > 0 Then
            found_count = found_count + 1
            Call Rhino.LayerVisible(layers(i), False)
        End If
    Call Rhino.Print(found_count)
End Sub

I get 165 as found_count and all the desired layers are turned off.

This is one aspect of the problem, another was importing the files that constituted this one big file. There are instances where Python/RhinoCommon is simply unable to write correctly to the layer table and causes the whole import script to error out. I will try to create a compact example of that as the combined files are over 500 Mb, but I have 3 of the 168 files that just refuse to have the filename written as a top level layer. I can see nothing in the name (no special characters, just ascii letters and numbers) that should prevent them being used to create a layer…

Anyway, not a happy camper at the moment, faced with rewriting my import script in vb rhinoscript because I know it should work… :confounded:


if snippet in names[i].lower():

lx = Rhino.RhinoDoc.ActiveDoc.Layers.FindByFullPath( names[i], True )
ly = Rhino.RhinoDoc.ActiveDoc.Layers[ lx ]
id = ly.Id

rs.LayerVisible(id, False)

Mitch, not sure it works … but to avoid rewriting in VB …
Does editing like that make it work ?

Hi Mitch,
Sorry about your frustrations …
The VB code looks like it would make a sub layer of a “textbit” parent layer invisible even if the sub layer didn’t contain “textbit”.

Interesting. Yes, so it looks like the VB function is also wrong, it should turn off the parent layer if it contains textbit, but it should only “half turn off” the sublayers (half off lightbulb). If you turn back on the parent layer the sublayer should also then turn back on, which it doesn’t.

In my case, since I know the textbits are only in sublayers, it doesn’t really matter, but this also needs to be looked at.


I have a look in a bit, thanks Emilio.! --Mitch

Nevermind, Mitch, it was a stupid idea.
rs.LayerVisible() does exactly the same thing … sorry.

Hey Mitch,

This probably does what you want

import scriptcontext as sc
for layer in sc.doc.Layers:
  if "textbit" in layer.Name.lower():
    layer.IsVisible = False

You can uncomment the “SetPersistentVisibility(False)” line if you want “textbit” sub layers to stay hidden after their parent “textbit” layer has been turned back on.

The lightbulbs might not get refreshed so collapse and expand the tree to redraw

Hmm, that’s one of the first thing I tried… Didn’t seem to work - if it had my rant might not have been posted - but maybe just the lightbulbs were wrong. I’ll check again. My main problem is the import thing mentioned afterwards, I had to just skip the bad stuff because I don’t have time now, but I will try to put together an example as soon as I can.

Thansk for looking, greetings from la suisse romandie, --Mitch

OK, so I finally managed to do some serious testing and narrowed this one down somewhat. Attached is my import script - which I have re-written so many times, but is now mostly in RhinoCommon, as the rhinoscriptsyntax version didn’t work well at all - and 3 test files (may be over the limit). Put all 3 files unzipped in a folder, open a blank file, then run the script and browse to the folder. Makke sure in Options>Files, it’s set to “Use complete layer tree from source file”.

I am first getting a “Layer name in use” popup that I don’t know where it’s coming from… Then, you will likely get an error message that nnn bla bla doesn’t exist in layer table and the script will error out.

Now, if you start taking some of the spaces out of the filenames, it will start to work better. With all the spaces removed, it runs all the way through, but you still get the “layer in use” popup…

Anyway, if anyone can see what’s going wrong here… great. No time pressure, I already had to workaround this stuff manually.

Thx, --Mitch

BatchImportDrawerFiles-Test2.py (3.4 KB)

031 first victim - poignée_tiroir.zip (2.0 MB)
072 second victim - exercice 3.zip (428.4 KB)
118 third victim - poignée_tiroir.zip (2.6 MB)

Hi Mitch,

If you step through your script you’ll notice that it’s flattening out the imported layer tree so all the nodes are directly under the “file name” layer. The “layer in use” msg pops up because some of the sub layers that are trying to be copied to this same layer have the same name (ex: “Tiroir - Copy - Copy”)

This might be simpler

add layer for file to be imported:

layerFullPath = rs.AddLayer("FileName")
fn_layer = sc.doc.Layers[sc.doc.Layers.FindByFullPath(layerFullPath, True)]

import form file …

re parent imported layers:

root_layers = [layer for layer in sc.doc.Layers if layer.ParentLayerId == System.Guid.Empty and layer.LayerIndex > fn_layer.LayerIndex]
for layer in root_layers:
  layer.ParentLayerId = file_name_layer.Id