"Pack" and Send a Large Set of Data Without Losing the Data Tree

HI

I am working on a large definition.

For better organization of the logic i have divided the projects in subgroups in different parts of the canvas.

MY GOAL : i need to transfers large set of datas from 1 place to the other and access those data where i need to use them , i need the data structure to be exactly the same downstream…to do this i’d need a “PACK component” with zoomable interface to set NR of inputs…i then would need an “UNPACK” COMPONENT that can match nr of outputs automatically ( same as explode tree ) and that return same identical data structure and path number for the data

I have been using “entwine component” successfully until now and it worked because all list in the branches were always simple flattened lists ( no tree )…but in this case i need to transfer a list of booleans with a specifci tree and i am not able ,i tried to use “wrap List” / "unwrapp list " ( by Metahopper) but i lose the data structure , see TEST2 attached file.

is there such a component that allow me to simply pack any sort as shown above unpack them wherever i need ? it would be very useful to organize the data and the job in massive definitions.

thanks.

20261008 TRANSFERING DATA.gh (26.6 KB)

Right click Entwine to access the “Flatten/Graft” options of the component. (I am talking about the hanging tab, not the inputs)

Hi @Volker_Rakow , i tried either flatten or graft and both are not doing what i Need , they both change the data tree , with flatten i lose the tree , with graft i add a branch and when i esplode It back and.match i have a ton of branches ..

I am notnin the office now , Need to try later.

That said i thino that a “pack” “unpack” component that can compress any sort of data and its tree inside different index would be very useful..i havent seen anything like that until now


20261008 TRANSFERING DATA VR1.gh (58.4 KB)

Note that this will never be dynamic because Explode Tree is not dynamic.

@maje90 , i tried you C# component taken from this thread but it does not fix my problem , it actually produce same result as the Metahopper components

your script :

here is MetaHopper wrap/unwrap

what i need is nothing but a many input component that do nothing but storing and packing data in a single object , it should work with any sort of data type and allow user to send data it remotely without changing anything , the only changeable thing is the nr.of inputs and the corresponding nr of output in to the unpack ( opposite ) component

Hi @Volker_Rakow , and thanks! Yes, this is exactly what I need to do. Thanks a lot!

I just wonder what is holding the GH developers back from creating a native GH component that works similarly to Entwine, but simply allows grouping N wires into one, and another component that decompresses one wire back into many without changing anything.

This would be very useful for organizing definitions and keeping the canvas cleaner.

You can flatten a datastream and then later unflatten with original stream as guide data tree

YES AND NO , I mean , under a logical point of view you are right , i was able to restore the tree structure but it does not solve my need.

I want a single wire but when i entwine everything in a single wire i can either flatten or graft but it messed up the tree again and if i want it to work i need N+1 wires as first image = hard to handle when entwine has several inputs

like this it works :

i need a single wire like this below in order to keep canvas clean and to ease connections and mainteinance and modifications

conclusion : the entwine should have 3 option instead of 2 ..it should have

  • "flatten "
  • “graft”
  • “nothing”

You cannot use Unflatten Tree to split a data tree.

@cloudsvisitor77 Please mark a solution.

thanks for your solution @Volker_Rakow , i remember facing this problem other times in the past and yes , thats helpful

that said , am i wrong when say this ?

i think that having an entwine that return unchanged data thus allowing to transfer lot data in a single wire could be very useful , this would actually be the result :

  • 1 main data flow “grouped” data
  • 2,3,4 unpacked
  • 5 packed data to be added to the main data flow

I wouldn’t worry about it. For me, canvas cleanliness is not a good enough reason to want to combine and unentangle data like this.

Yes. A stream can only ever carry a single data tree. Either you flatten data while entwining, so that branches from different sources with matching branch addresses merge, or graft so that each data set is a subset of the whole.

What you are looking for, I suppose, is some sort of data tree splitting component that has expandable outputs and splits at branch depth. Someone could make this component… the question is if it would be useful. Expandable output components are generally sketchy. They do not expand or contract automatically. The user needs to “Match outputs” from the context menu. And even if the number of outputs would update automatically, how would you decide wiring? Say on one solve, the component reduces to one output. Then the next expands to five. Or a hundred. What then? But it’s not a bad idea.

Here is a python script (~90% vibe coded) that reverses the Entwine + graft operation. It splits the incoming data by first branch index, makes sure the component has the right number of output nodes, and routes the branches to the correct output while stripping the extra path index added by the graft operation of Entwine.

20261008 TRANSFERING DATA python.gh (36.1 KB)

import Grasshopper as gh
from Grasshopper.Kernel.Data import GH_Path, GH_Structure
from Grasshopper.Kernel.Types import GH_ObjectWrapper
import RhinoCodePluginGH

def reverse_entwine():
	# 1. Group the paths by their first index
	grouped_branches = {}
	
	for i in range(D.BranchCount):
		path = D.Path(i)
		branch_data = D.Branch(i)
		
		if path.Length > 0:
			first_idx = path[0]  # This represents which Entwine input it came from
			
			# Create a shortened path by removing the first index
			new_path_indices = [path[j] for j in range(1, path.Length)]
			if not new_path_indices:
				new_path_indices = [0]
			new_path = GH_Path(*new_path_indices)
			
			# Use GH_Structure[GH_ObjectWrapper] to satisfy IGH_Structure
			if first_idx not in grouped_branches:
				grouped_branches[first_idx] = GH_Structure[GH_ObjectWrapper]()
			
			# Wrap raw python/rhino objects into Grasshopper Goo wrappers
			wrapped_data = [GH_ObjectWrapper(item) for item in branch_data]
			grouped_branches[first_idx].AppendRange(wrapped_data, new_path)

	# 2. Determine how many outputs we need based on the highest Entwine index found
	target_count = max(grouped_branches.keys()) + 1 if grouped_branches else 1
	current_count = ghenv.Component.Params.Output.Count
	
	# 3. Schedule a topology change if the output count doesn't match
	if current_count != target_count:
		def callback(doc):
			params = ghenv.Component.Params
			
			# Add missing outputs
			while params.Output.Count < target_count:
				new_idx = params.Output.Count
				nickname = "R"
				p = RhinoCodePluginGH.Parameters.ScriptVariableParam(nickname)
				p.Name = "Entwine Out {}".format(new_idx)
				p.Access = gh.Kernel.GH_ParamAccess.tree
				params.RegisterOutputParam(p)
				
			# Remove excess outputs
			while params.Output.Count > target_count:
				last_idx = params.Output.Count - 1
				params.UnregisterOutputParam(params.Output[last_idx])
				
			params.OnParametersChanged()
			ghenv.Component.ExpireSolution(True)

		ghenv.Component.OnPingDocument().ScheduleSolution(5, gh.Kernel.GH_Document.GH_ScheduleDelegate(callback))

	# 4. Safely push the modified GH_Structures to their respective outputs
	for i in range(ghenv.Component.Params.Output.Count):
		output_param = ghenv.Component.Params.Output[i]
		output_param.ClearData() # Prevent data accumulation on refreshes
		
		if i in grouped_branches:
			output_param.AddVolatileDataTree(grouped_branches[i])

# Run the execution routine
reverse_entwine()

Ask you may receive!

This script uses a callback function to modify its own outputs without the right click menu step. It seems to work fine on this small file, but I’m not sure it wouldn’t do an entire re-run of a large solution and waste a bunch of time or something.

AWSOME JOB @Measure I am going to use and test it. i really appreciate

in simple word what i need is nothing but an entwine component that does not flatten or graft…it only wrap and stream in a single object complex sets of data and stream this data somewhere , i dont need input and output to change or update automatically cause it is just a placeholder and wrapper that make this set of data available everywhere down the definition., wherever i need

i have been using this approach on arranging massive definitions for a while now and i can assure that this practice helps a lot on keeping massive scripts scalable, ordered , easy to update, read and modify

Yes. And what I am trying to explain is that such a thing is not possible with in the bounds Grasshopper’s concept of data structure. There is no “entwining” that does not flatten or graft…

It doesn’t matter. I understand what you mean essentially.

For completion’s sake, some native Grasshopper variants:

Much more useful to me would be a Tree Branch component that:

  • takes masks instead of paths
  • provides separate outputs for each branch of provided masks
  • has a renumber bool input

:face_holding_back_tears: :folded_hands: If you are ever up to it.

The Divide Branches component is pretty close to this.

From the Tree Sloth plug-in? Kind of.