Renaming a sub-layer with Python

I notice that when using the RenameLayer method in Python, any renamed sub-layers inherit the name of the parent layer. Is there a way to avoid this? In the following illustration, I used the RenameLayer method to change “Ringo” to “Richard”. The results are shown below.

Thanks,

Dan

This seems to work.

import rhinoscriptsyntax as rs
layer = rs.GetLayer()
if layer:
    rs.RenameLayer(layer, "Richard")

Yes, that works here too. The problem must be related to how I am selecting the layers. What I am attempting to do is to create a find/replace tool for layer names. Here is what I have that is producing the results shown above:

import rhinoscriptsyntax as rs

def LayerFindReplace():
findText = rs.StringBox(“Enter the text to find”, None, “Layer Find/Replace”)
if findText is None:
return
else:
replaceText = rs.StringBox(“Enter the replacement text”, findText, “Layer Find/Replace”)
if replaceText is None:
return
else:
layers = rs.LayerNames()
if layers:
for layer in layers:
name = rs.LayerName(layer, False)
if findText in name:
newtext = layer.replace(findText,replaceText)
rs.RenameLayer(layer,newtext)

if name == “main”:
LayerFindReplace()

Hi Dan,

I did not try to run your code (might be useful next time to enclose your code with back ticks) but from what it looks like, you need to change the line:

newtext = layer.replace(findText,replaceText)

to

newtext = name.replace(findText,replaceText)

Thank you for that link about enclosing the code. I knew there was a way to do that, but I couldn’t recall what it was. I recall Mitch mentioning it within the last couple of weeks.

Your suggestion works for me. It’s obvious now that you mentioned it. Good old hindsight!!

Thanks,

Dan

Hi @DanBayn , have you been so kind to save out + upload this cool script with this enclosure - so that I may download and use it?

Here it is.

LayerFindReplace.py (806 Bytes)

You may find that this errors out if you have sublayers and you change the name of a sublayer - depending on the order in which it was in the layer table… Also, if the same substring is contained in more than one level of a nested sublayer, it may not change all of the instances of that substring in the full layer name.

Layer name find/replace is complicated with sublayers because of the nesting involved.

Hi Mitch,

Yeah, I wouldn’t be surprised one bit. At the time we had a department that requested this script. I don’t believe they ever use sub-layers. That’s probably why no one ever flagged this as being unreliable.

Dan

Here is a first attempt at a find/replace for layer names. Works recursively on sublayers. Please report any failures… :stuck_out_tongue_winking_eye:

ReplaceLayerNames.py (1.2 KB)

Hi Mitch,

I’ll test this in the morning.

Thanks,

Dan

1 Like

Hi Mitch,

I’m finding that if you have sub-layers named the same and you try to change them, Rhino will crash to the desktop.

image

Try changing Layer 04 to something else.

Merde, yes, I see that - OK, back to the drawing board. The recursion must be sinking into an infinite loop or something. Every time I mess with layer functions I always regret it. :confounded:

Hello,

This seems to work : rename_layers.py (658 Bytes)

I think the problem is that you have to start by renaming the top layer and then work your way down taking account of the renamed top layer. Sorting the layers by level and then getting the new name at each step solves it.

import rhinoscriptsyntax as rs

__version__ = 0.
__author__ = "Graham Knapp"
__homepage__ = "https://discourse.mcneel.com/t/renaming-a-sub-layer-with-python/14779"

def main():
    old = rs.StringBox("Text to replace", None, 'Rename Layers')
    if not old:
        return
        
    new = rs.StringBox("Replacement text", old, 'Rename Layers')
    if not new:
        return

    for i_layer in sorted(rs.LayerIds(), key = lambda x: rs.LayerName(x).count("::")):
        name = rs.LayerName(i_layer)
        if old in name:
            rs.RenameLayer(name, name.split("::")[-1].replace(old,new))

if __name__ == '__main__':
    main()
1 Like

Hi Graham,

I’ll take a look at your script. I have a version that works, but it doesn’t iterate indefinitely. So if there were say, 20 sub-layers deep, it wouldn’t change them all. I’d be good for 12 with my current version. For us, we would never even get close to that. But now this has become a personal challenge. I don’t like to give up! :slight_smile:

BTW… Tobias has a very nice tool that handle finding and replacing layer names, among other things. He was generous enough to share it, and it’s probably what we will use, but like I said, I don’t give up easily.

Thanks,

Dan

I didn’t have time to get back to this until now, here is a version that might now work…

ReplaceLayerNames.py (1.4 KB)

I’m always wary of working with sublayers, for if you change a layer name that has children, it automatically changes the childrens’ full names as well. Then you might end up with “Layer does not exist in the layer table…” error message if you are iterating through a layer name list made beforehand. That’s why in most of my scripts concerning layers I start at the bottom most level and work up via recursion.

Working with layer ID’s is also a good idea as they do not change if the layer name changes. What’s not obvious from the rhinoscriptsyntax Help doc is that most all rs methods that concern layers can accept either layer names or layer ids. However, they do not generally return layer ids, only full names.

Probably better to do all of this in RhinoCommon.

1 Like

Hi Mitch,

Yes, this version works well. I think you’re right about using layer ID’s instead of names. In my experiments I saw that warning “Layer does not exist in the layer table" many times. Graham’s solution also uses layer ID’s.

I’d say this one is solved three different ways! :slight_smile:

Thanks,

Dan

1 Like

A non-recursive approach (that might be relevant here) is to get all the layer names, sort these by depth, and then iterate over this list of names (and rename/delete layers etc).

Edit: I think this is what @Dancergraham already suggested above. As you were :slight_smile:

And just in case, here is a version which allows you to limit the replacements to specific selected layers.
FWIW…

ReplaceSelectedLayerNames.py (1.7 KB)

1 Like

Thanks so much once again, @Helvetosaur !