Open als0052 opened 3 years ago
You mean like this?
from anytree import Node, findall_by_attr, RenderTree
lines = ['~Assembly1~SubAssembly1~SubSubAssembly1~SubSubSubAssembly1~Component1',
'~Assembly1~SubAssembly1~SubSubAssembly1~SubSubSubAssembly1~Component2',
'~Assembly1~SubAssembly2~Component1',
'~Assembly1~SubAssembly2~Component2',
'~Assembly1~SubAssembly2~Component3',
'~Assembly1~SubAssembly2~Component4',
'~Assembly1~SubAssembly2~Component5',
'~Assembly1~SubAssembly2~Component6',
'~Assembly1~SubAssembly2~Component7',
'~Assembly1~SubAssembly2~Component8',
'~Assembly1~SubAssembly2~Component9',
'~Assembly1~SubAssembly2~Component10',
'~Assembly1~SubAssembly2~Component11',
'~Assembly1~SubAssembly2~Component12',
'~Assembly1~SubAssembly2~Component13',
'~Assembly1~SubAssembly2~Component14',
'~Assembly1~SubAssembly2~Component15',
'~Assembly1~SubAssembly2~Component16'
'~Assembly1~SubAssembly3~SubSubAssembly1~SubSubSubAssembly1~Component1',
'~Assembly1~SubAssembly3~SubSubAssembly2~SubSubSubAssembly1~Component1',
'~Assembly1~SubAssembly3~SubSubAssembly3~SubSubSubAssembly1~Component1',
'~Assembly1~SubAssembly3~SubSubAssembly3~SubSubSubAssembly2~Component1',
'~Assembly1~SubAssembly3~SubSubAssembly4~Component1',
'~Assembly1~SubAssembly3~SubSubAssembly4~Component2',
'~Assembly1~SubAssembly3~SubSubAssembly4~Component3',
'~Assembly1~SubAssembly3~SubSubAssembly4~Component4',
'~Assembly1~SubAssembly3~SubSubAssembly4~Component1',
'~Assembly1~SubAssembly3~SubSubAssembly5~Component1',
'~Assembly1~SubAssembly3~SubSubAssembly6~Component1',
'~Assembly1~SubAssembly3~SubSubAssembly7~Component1',
'~Assembly1~SubAssembly3~SubSubAssembly8~Component1',
'~Assembly1~SubAssembly3~SubSubAssembly9~Component1',
'~Assembly1~SubAssembly3~SubSubAssembly10~Component1', ]
def from_assembly_line(root: Node = None, line: str = ''):
nodenames = [x for x in line.split('~') if x] # removing empty items
# root node
if root is None:
root = Node(nodenames[0], parent=None)
# iterating from the second element
for nodeind, nodename in enumerate(nodenames[1:]):
parent_candidate = findall_by_attr(node=root, value=nodenames[nodeind])
# todo check len(parent_candidate) > 0
if not findall_by_attr(node=parent_candidate[0], value=nodename):
Node(nodename, parent=parent_candidate[0])
return root
if __name__ == '__main__':
_root = None
for _line in lines:
_root = from_assembly_line(root=_root, line=_line)
print(RenderTree(_root))
That looks like it'll work. I think I long ago found a work around to my issue above but I was hoping that this could become a more easily used feature in future releases. That way you don't have to write your own function to do it, even if it is a pretty simple (in hindsight) function.
Something more general that I would like would be a function to turn a list like this:
l = [('Europe", "Italy", "Rome"),
('Europe", "Italy", "Milan"),
('Europe", "France", "Paris")]
into a tree:
Europe
Italy
Rome
Milan
France
Paris
The reason is that I have many hierarchies stored in csv files and with pandas and such a function I can easily convert them to trees. It would also solve your problem, because you can just split each of your strings.
Here are sample implementations for my ideas above:
def from_rows(rows, node_factory=anytree.Node, root_name="root"):
created_nodes = {}
root = node_factory(root_name)
for row in rows:
parent_node = root
for depth, col in enumerate(row):
if (depth, col) in created_nodes:
node = created_nodes[depth, col]
else:
node = node_factory(col)
node.parent = parent_node
created_nodes[depth, col] = node
parent_node = node
return root
def to_rows(root, str_factory=str, skip_root=True):
index = 1 if skip_root else 0
for leaf in root.leaves:
yield [str_factory(node) for node in leaf.path[index:]]
Update 2024-01-06:
I implemented this in littletree using functions Node.from_rows
, Node.to_rows
.
I've got some files I'm trying to parse into a tree (a FEM assembly tree actually) and need to take a list of lists and create a tree form it. Because of the way I get the raw input that I'm parsing (TCL script) all the lists have the full path, much of which is repeated in each list. I'm sure I could get this working eventually without a 'batch node creator' but I wanted to throw this out there anyways for consideration that such a batch node creator be added in the future.
Below is a (hopefully understandable) minimum example copied and pasted from a markdown export of a Jupyter notebook. I think this request might be similar to others made previously and if so feel free to close this one and/or link it to other issues.
Sorry for the book-length post!!
Make the Tree Manually w/ anytree
Parse the TCL Script Output File
Looks something like this (
~
delimited; contents pasted here so as to not includeExampleTree_featureRequest_raw.txt
):Read in the raw TCL Output File
Parse the content into list of lists
Desired Feature
A way to 'batch create' a node tree. Some command that will take in a list of delimited node-childNodes-etc. and create a valid Node object from it.
Example:
The above should produce the same result as doing it by hand:
Related Issues
Open
Closed
Node.path_to
method?Semi-Related Issues
Open
Closed
children=[...]
stuff