When working with 1:N components (Divide Curve, Shatter, Explode, and many others), the output always gets an extra branch level. I know why it happens, but in many cases I do not need that level, so I have to place a Trim Tree after each one of these components. In a definition with several of them, this means a lot of Trim Tree components on the canvas that add unnecessary noise.
The right-click context menu on inputs/outputs already offers Flatten, Graft, and Simplify. A fixed single-level Trim (called UNGRAFT more easily) would be the natural counterpart to Graft; one adds a level, the other removes it.
It would work just like the other modifiers: an explicit component with more settings versus a right-click option with a fixed default. For example, Flatten in the right-click menu defaults to {0}, while the explicit component lets you set the output path. Similarly, Ungraft would act as a Trim modifier with default to depth 1, while the explicit Trim Tree component would remain available for anything more specific.
I see this topic has come up cyclically over the years but has either received no response or unclear ones. This is not about finding a different way to do it; it is purely a quality-of-life improvement to keep the canvas clean.
I am curious about why it has never been considered. Is it not important enough? Too niche? Not impactful on most usersā workflows? Or is it one of those advanced topics where whoever would benefit from it already knows how to manage trees, so it never builds enough pressure? Or is it simply considered outdated at this point, with the focus being on Grasshopper 2, scripting, or vibe coding?
The problem is, there are components that add more than 1 branch depth.
Other than this, my use of Trim Tree is rare. I only use it when a component threatens internal zeros (like {0;0;0;n;0;n}) Otherwise, I just let the branch paths grow. They eventually disappear, or I clean up at the end with Simplify or Match Tree (because simplify has problems with {0;0;0;0;0} as the only branch in the tree structure)
Regarding components that add more than one level: One edge case might be Divide Surface, but it is one of the very few that work differently. The vast majority of components that are not in the 1:1 category add exactly one level, so a depth-1 modifier would cover 99% of cases. And just like the other modifiers, nobody would be forced to use it; the explicit Trim Tree component would remain available for anything more specific
As for letting paths grow and cleaning up at the end, I think it works well when the definition has a mostly sequential flow. When you need to merge or exchange data between parallel streams that have accumulated different branching histories, path mismatches start to show up, and that is where controlling the tree structure at the right points becomes important. If you try to fix with Simplify, you risk removing zeros that were actually carrying meaningful structure. In those cases, I find that placing a Trim in the right spots is a cleaner approach, and that is where a right-click option would make the biggest difference
Below are a few suggestions that you might find useful :
1. Rather than ādebuggingā 1:N components by placing a Trim Tree component after them each and every time you use them, just do it once, then convert it into a cluster and then save this cluster as a User Object. When naming the User Object, one option is to use the same name as the original component and append something to differentiate it from the original, e.g. āShatter_xā, BUT it can make canvas searches faster if you instead prepend a rarely used or special character, e.g. ā.Shatterā or ā_Shatterā (i.e. less typing to find it) ā you can also develop your own vocabulary of prefixes to represent different modifications, e.g. a period (.) for trimming, an underscore (_) for debugging, etc.
2. If the above suggestion seems viable, before diving in, consider whether Trim Tree works exactly how you would like it to. In my experience, Trim Tree (like many other components, e.g. Simplify, Point Groups, Split Tree, ā¦) is flawed in a way that makes it unsuitable for parametric scripting. In the case of Trim Tree, it crashes if the Trim Depth input (D) is equal to or smaller than the branch depth of the Tree input (T), which can easily occur with variations in upstream data structure. Thereās a plug-in (Tree Frog, I think) that has a component āTrim Safeā that addresses this but, in my opinion, the whole concept of manually specifying a Trim Depth is flawed and very āanti-parametricā. So, in consideration of the workflow you describe above (data streams diverging, undergoing differing branch modifications in parallel streams, and then re-converging), I just wanted to suggest an alternative to debugging every 1:N component in the native gh library ā see attached TrimMatch.gh. Iāve only been using this for a while but think it works well in a kind of hybrid of the work flows that you and Volker describe, i.e. let the zeroes grow whilst in parallel streams and then trim them parametrically before re-convergence by consciously identifying which upstream component the current path depth should match .
On the first point: it is an interesting strategy and I will keep it in mind, thanks, but I do not think it fits this case. One would have to create and maintain a set of clusters for dozens of components, each with proper icons and layout to keep things clean, filling up the toolbar and risking a mess. That is a lot of effort to compensate for a feature that could be a single native option available to everyone out of the box. One could argue that if I need it that badly I should just roll up my sleeves and do it, but that is exactly the point of my post: understanding why a solution like this has never been considered by the developers.
On the second point: if you try to bring a tree down to zero levels (using a depth equal to or greater than the tree depth), the component will naturally error out; that is expected, not a flaw. When used correctly, Trim Tree is perfectly parametric. I think you might be referring to Shift Path Safely from the TreeSloth plugin. Also, manually specifying a depth is not anti-parametric if it is a fixed, preset value. It would be anti-parametric if you had to inspect and adjust it every time.
What I am proposing, and I am not the first, is integrating a version of the command in the right-click output menu with a preset value of 1, essentially an Ungraft option that sits right next to Graft: one adds a level, the other removes it. If someone applied it on a 1:1 component where the output is a single list, it would error out, and rightly so. Whether it should error or silently leave the tree unchanged would be a design decision for the developers, similar to how Shift Path Safely from TreeSloth handles that case. My question is why this has always gone unheard.
Thanks for your script, I will have a look at it as soon as I can. I think though that it addresses a different concern: you are talking about matching tree structures across different streams, while my point is about quality of life in the punctual control of a single tree.
Shift already has meaning. It is an umbrella term for trims that also include trims from the front of branch addresses (paths). Outside of this are the tree collapses that can occur in the middle of branch addresses and can only be accomplished by means of Path Mapper or Replace Paths. Iāve always felt the term Shift to be a bit of a misnomer. Without being informed otherwise, I would have assumed it meant to āshiftā the branch address in the same way lists are shifted {0;1;2;3} ā {3;0;1;2}
Interestingly, while Graft grafts at the end of a branch address, thereās no way to force this at the front of the branch address. Short of, again, using Path Mapper or Replace Paths. Not that Iāve ever come to an immediate need of this. It would be like Entwine-ing. Actually exactly like entwining, except working with a list instead of separate streams.
Stunt would be like a ādonāt growā modifier. Donāt expand, or further graft the tree. Or a āflattenā of the local branch depths normally created by a component.
Instead we are arguing that instead of us doing it, the developers should and make it an permanent part of Grasshopper 1. Because going through all the components and adding this functionality in a way that jives correctly with them is basically what they would have to do.
Shift already exist as a native component, as @Volker_Rakow explained.
I was thinking about the context menu where you already have Flatten, Graft, Simplify, Reverse and the analogy with Graft and what is the meaning, cutting back the new layer, so I used Ungraft to use something self-explaining, as the first guy I saw taking about it here, but I have to say Stunt is very nice too
From my experience using simplify is not a good practice. Because when you are working with multiple branches algorithm will work fine, but when you suddenly need to run your algorithm on one branch, (lets say you are making pattern for multiple walls, but decided to make it for one wall), simplify will give you different results, trimming more zeros where it should not, so some other downstream data modification - trim tree, split tree or path mapper can shift lists into nothing or just brake.
So I use trim tree after all components that do not really create a new meaningful data tree structure. Also it helps to understand how your data tree looks with a panel at a glance
{0;0;0;2;0;3;0} vs {2;3}
I feel like I should outline the basic conflict here:
Grasshopper components follow the concept of adding as many depths of hierarchy to a path of an output as would be necessary to accomodate the most complex constellation of data structure given to it as input. If the input data is less complex (just a list, not a tree), the component still outputs the maximally necessary extra depths of path hierarchy, resulting in āextraneousā zeros in the branch addresses of the data structure. For users who understand branch paths only as a reflection of the hierarchization state of their data, the extraneous zeros seem āuncleanā and āconfusingā. Which, in a situation where there are so many zeros inflating the branch paths of your data that you need to expand the Param Viewer to read them, they are. But in addition to being a reflection of hierarchization state of data, branch paths carry in the depth length of their paths the procedural footprint of how they were made and this is necessary information in order to be able to consistently compared and manipulate different sets of results originating from the same definition.
Now, there are alot considerations as to how to make data structure more legible. Suirification argues that all paths should be reduced to pure reflection of data hierarchization, and, certainly, you could program all the Grasshopper components to behave in this way; making components adapt to their inputs and only output the necessary extra depth of path heirarchy. But this is at odds with how the tools for path manipulation operate. Then, there are considerations such as the above, where the user can decide at what points in the script the definition should assume no higher complexity (simple lists) and insert a Trim Tree component or variant thereof as a output modifier to clean up the path structure. This is basically how Grasshopper is set up now. Lastly, we could also consider a two-tiered system, where Grasshopper holds both the current and simplified path setups in mind and shows the user which ever variant is useful to him in the moment. This basically like a simplified path overlay while Grasshopper continues to work behind the scenes with the current path paradigm.
I think we might be overcomplicating this: components in the 1:1 category do not add any extra level, components in the other categories add exactly one level (and two in the very rare cases with grid-type outputs). This behaviour is consistent and works well.
For simple, sequential scripts, the data tree does not even show up when hovering over inputs or outputs; everything stays as a flat list and users may not even be aware of the tree structure. At some point they might notice with a panel the accumulated zeros and clean them up somehow. When scripts become less linear or involve tree inputs, the structure becomes visible and the user starts to notice that it grows and needs more careful management.
Unpopular opinion regarding Suirify: it is essentially Simplify on steroids, working also on single-branch trees. Like Simplify, it is a trap, and arguably a worse one. From what I see on the forum and in tutorials, it is mostly misused: people spam it because it is small and shiny, and they walk away thinking they have learned data tree management, when in fact they are unlearning it. In my opinion it has done more harm than good. Its actual use case would be to unify inputs coming from external sources with uncontrollable structure before merging them into a definition. Or as a final cleanup in a simple, single-list sequential script. But every time I see it used in practice, it is just a substitute for Trim, and a misleading one.
Iāve never find once a practical scenario where a logic without using Simplify stops working if I use Simplify.
⦠so, I use Simplify everywhere to keep thing more readable. Happy life.
Until today, I never used Suirify once and still canāt understand where I would need itā¦
Trim tree. I use it often, but strictly after a Simplify.
{0;0;x;0;y;0} you use Trim tree(1) , it fails its scope.
{0;0;x;0;y;0} > Simplify > {x;y} > Trim tree(1) > done.
Personally, when datatrees go past 3 levels of complexity (real levels, not zeroes), I find it simpler to go inside a c# and everything become much simpler⦠and you add multithreading too.
win-win situation.
Grasshopper have probably the most complex datatree handling tools you can find.
Itās ālateā and unlikely some big changes will happens.
āIf it works, donāt touch itā
Is someone trying GH2? (I never have the timeā¦)
Maybe something was done there?
No, the opposite.
Complex datatree manipulation are needed because of how visual programming language works: everything happens all at once, simultaneously.
In coded workflow you can simply iterate inside well-defined ābranchesā without any risk to mix or wrong-match your lists.
You can effortlessly create your own methods that would add another datatree level in VPLā¦
Actually I never even had the need to avoid the complexity, in my experience coding simply let you bypass the whole problem without effort.
Also, the best part is creating you own coded components and mixing it with normal Grasshopper flow.
Take the best perks of VPL and code at the same time. Absolute win.
Clusters should work like āmethodsā in code, but instead often they fails. I never use them.
Grasshopper Hops instead are much nearer the idea of āmethodsā in code, you can specify if an input is a single item, a list or a datatree ⦠but they are more slow to add in a document and to maintainā¦
I remember asking David Rutten to add a more flexible āGroupā to handle this matter⦠no idea how things are going in GH2ā¦
Itās a matter of luck and applications. Consider your example tree {0;0;x;0;y;0}. Imagine you have to split it and you end up with the branches with all x OR all y being = 0. If you simplify you break the structure
More unpopular: simplify and suirify should not exist (just kidding (maybe))