Grasshopper

algorithmic modeling for Rhino

Hello,

I have been doing a lot of python scripting lately and I've been running into a lot of issues with how geometry is handled through iterations. Here is an example of one such problem:

I am using itertools to give me all possible permutations of object combinations. The result is System.Guid objects in lists. I have searched the forums and keep getting stymied by my lack of understanding in how to handle geometry in Python. Could anyone help me solve this particular problem?

Thanks,

Shane

---------------------------------

EDIT:

I managed to fix the problem using this code found elsewhere on the board:


def ghDataTreeToPythonList(DataTree):
    
    """ Converts a GH datatree to a nested Python list """
    
    # Create an empty Python list
    pyList = []
    
    # Add the branches of the Gh datatree to this list
    for i in range(DataTree.BranchCount):
        branch = list(DataTree.Branch(i))
        pyList.append(branch)
        
    return pyList

def pythonListTGhDataTree(pythonList):
    
    """ Converts a  nested Python list to a GH datatree """
    
    # Create GH datatree
    dataTree = gh.DataTree[object]()
    
    # Add pythonlist sub lists to dataTree
    for i,l in enumerate(pythonList):
        for v in l:
            dataTree.Add(v,gh.Kernel.Data.GH_Path(i))

    return dataTree

I suppose my real question now is what the heck is going on with this script? The big stumper is "dataTree.Add(v,gh.Kernel.Data.GH_Path(i))".

It appears python in grasshopper automatically gives attributes to trees, so "DataTree.BranchCount", and a gh.DataTree, when defined, requires a type of object or the generic "object". I almost understand how this all works, aside from what is happening in the paragraph above, as well as knowing when an operation like this is necessary. I took a guess at applying this snippet to my code, but other times I'm totally flummoxed.

Thanks again,
Shane

Views: 2137

Replies to This Discussion

Hi Shane

as you already figured out, trees are a major roadblock for new scripters -- in Python, C# or any other language we support. 

The issue you are facing derives from trees.

The Grasshopper SDK does not understand enumerables of enumerables (for example, Python nested lists). For this class of data, it only handles properly a special type, written with several goals in mind, and that therefore has to compromise a bit on simplicity, which is the datatree data structure.

That snippet you copied embeds knowledge about both the Grasshopper SDK (which does not know about Python) and Python lists of lists (which do not know about datatrees); it converts between them.

Does this help?

Giulio
--
Giulio Piacentino
for Robert McNeel & Associates
giulio@mcneel.com

Giulio, is it worth adding your sample code for conversion between nested lists and datatrees [1] as a function in rhinoscriptsyntax/ghpython?

[1]: https://gist.github.com/piac/ef91ac83cb5ee92a1294

+1

Great idea. Although, perhaps it makes more sense (coupling-wise) to add them as functions of the GHPython component itself (maybe in ghenv)? 

Thanks Giulio, this does help.

So, in simplified terms for my beginner brain, while nested lists from python are similar in structure to Grasshopper trees, because Grasshopper manages data differently they are not interchangeable. The script I found and added to my post handles this by iterating through the python list and plugging values into a Grasshopper tree one at a time as they pop up in the loop. The script you posted to GitHub does this differently, I think, by making sure the structure of the trees/lists (missing values, nulls and all) get transferred intact. Please correct me if I am making an incorrect assumption.

I read over your GitHub example and believe I'm looking at a few advanced python moves that I'm not acquainted with, such as proc() calling itself within its own definition. The script I found is a little easier to digest, but my hangup is with Kernel.Data.GH_Path. I understand it is taking the value from the python list and plugging it into the proper tree branch, I'm just not sure how gh.Kernel.Data.GH_Path is referring  to a tree branch (and I'm ok with it being magical programming stuff, just curious). Would this still work if I was distributing a python list into two branches? Shouldn't dataTree.Add(x,y) know where it's own branches are and put the info there (I have no idea how dataTree.Add(x,y) works, so this is an ignorant question)?

Anyway, Thank you for your efforts here, I've conquered many other problems with scripting reading your posts.


Shane

Hi again Shane

>> The script you posted to GitHub does this differently, I think, by making sure the structure of the trees/lists (missing values, nulls and all) get transferred intact.

Well, that is a part of the story. The script the script up here handles a single list of lists, while the one in the link creates a datatress with arbitrary nested lists. By themselves, Datatrees embed more information than lists of lists. For example, datatrees can have non-existing as well as empty branches, and this distinction cannot be rendered fully with lists only.

gh.Kernel.Data.GH_Path(i) is the constructor of a new GH_Path object with i as input. This means that the branch will be first {0}, then {1}, {2}, etc, in Grasshopper terms. We then pass this information as the y argument in datatree.Add(x,y). This is because, in general, dataTree has no knowledge about where to add the item until you also pass the GH_Path to the Add function.

Does it help?

Giulio
--
Giulio Piacentino
for Robert McNeel & Associates
giulio@mcneel.com

Thanks Giulio, that helps clear things up. I wonder, what is the format for y in Add(x,y)? How do I pass multi-level paths (ie. {0;1} {1;1})? I see you are using System.Array, but that is a bit out of my depth.

Thanks,

Shane

If you use print(type(object)), you will be able to see the type name. You can then use the help to see method signatures.

For example, if you type:

import Grasshopper as gh

gh.DataTree.Add(

You will see this:

About System.Array; that is the way you can pass deeper levels to the Gh_Path constructor. For example,  gh.Kernel.Data.GH_Path(System.Array[int]([7,3]))

will create path {7; 3}. The signature is a bit long, but it does the trick. This is an alternative syntax:
a = gh.Kernel.Data.GH_Path(*[7,3])

Giulio
--
Giulio Piacentino
for Robert McNeel & Associates
giulio@mcneel.com

RSS

About

Translate

Search

Photos

  • Add Photos
  • View All

Videos

  • Add Videos
  • View All

© 2024   Created by Scott Davidson.   Powered by

Badges  |  Report an Issue  |  Terms of Service