Speckle V2 Grasshopper client - Assign nested properties

Hi there, Speckle people!
I was testing speckle V2 and the Gh client in particular when I came across the following doubt: What is the correct way to assign nested properties to a Speckle object. I have Rhino geometry that contains custom user data in the form of nested dictionaries. I figured out a way to assign nested properties using a combination of “create Speckle object” components but this feels messy and sort of unstable as it will probably break if the structure of the original dictionary changes. Is there a better way to do that?

Here’s an example of the dictionary - it is dynamic and changes from one object to another, so I need a flexible way to do all that:

{
  "group": "group_type",
  "prop1": {
    "1": { "properties": ["prop prop"], "id": "002" },
    "2": { "properties": ["other props"], "id": "003" }
  },
  "prop2": {
    "subtype": "subtype string",
    "tags": { "tag_1": "A", "tag_2": "B", "tag_3": "C" }
  },
  "prop3": "Wall1",
  "status": "status string",
  "prop4": {
    "subtype": "subtype_type",
    "tags": { "tag_4": "0", "tag_5": "0.1" }
  },
  "prop5": {
    "subtype": "subtype_string",
    "tags": { "a": "1", "b": "2", "c": "3" }
  },
  "comments": "some comment"
}

Thanks a lot! Any help is appreciated :slight_smile:

1 Like

Hi @Mariela_Tsopanova, and welcome to the Speckle Community! You can use the Create Speckle Object by Key/Value to generate dynamic objects (each with it’s different properties and values).

Creating a single object with single item values

Creating a single object with mixed values (item and list)

Creating multiple objects with mixed values

Notice that for single item cases you don’t really need to worry about the data structure, but in order to generate multiple unique objects, the data structure must match

Meaning, all keys at path {0} will generate one object. The key at path {0}[0] will be populated with the value at path {0;0} (wether its a list or a single item), and so forth. It can get quite tricky but its also super powerful.

I’ve also attached the file so you can poke around with it. Let us know how it goes :slight_smile:

CreateObjectsByKeyValue.gh (22.3 KB)

2 Likes

Ciao Maria, good to see you here!

Another possibility is to do that in C# or python.

In C# you can either temporarily cast the Speckle Base object to dynamic, or reference Core in the C# node (more messy).

Please note that if you are editing an object in a C# node, also the upstream object will be modified!

Here is how you can add a property or a set of properties in a C# node:

  private void RunScript(object x, ref object A)
  {
    ((dynamic)x).mycustomProp = "Prop assignd in C#";
    A = x;
  }

1 Like

Thank you very much both! I had a quick look at your suggestions and I would definitely love to give the custom GH component a shot.
I have no experience in C# so this looks like it might be a challenge for me. I managed to reproduce Matteo’s 2-liner above but I am not sure how to approach the whole nested prop issue afterwards.
I do feel a bit more confident in python so it might be a better match for me.

On a slightly different topic, V1 had a wonderful documentation of the API (Speckle), any chance there might be something similar for V2? I tried following the example from here (Introduction | Speckle Docs) but I am running into an error pretty much immediately when trying to receive the commit object → ValueError: not enough values to unpack (expected 2, got 1). Not sure how to interpret that.

1 Like

Hi Mariela,

Great to hear that! @iltabe has also been using Python to attach custom props to Base objects and might have some tips to share…

Regarding the API, in v2 the graphql explorer is your best friend, which is also self-documenting. GQL has a bit of a learning curve to get comfortable with it, but it’s quite powerful! We’re due to write some more examples on how to write queries, but you can see plenty of examples in our code.

For any issues with the Pyhton SDK you can open a new thread and someone from the team will help you!

2 Likes

Ciao Mariela,

Speckle is now very smart. You can assign a python dictionary as a property and it will just expand it properly when added as input of the ExpandSpeckleObject component (thanks @AlanRynne!):


Here what I did inside the python component:

"""Provides a scripting component.
    Inputs:
        x: The x script variable
        y: The y script variable
    Output:
        a: The a output variable"""

__author__ = "iltabe"
__version__ = "2021.06.07"

myObjectExtended = myObject.ShallowCopy()

def main(myObjectExtended):
    for key, value in dictProps.items():
        myObjectExtended[key] = value

main(myObjectExtended)

Note that this might have a problem if you are relying on the Speckle kits to convert the object.
Are you using the data also outside grasshopper?
If so we can create a recursive function that create a new speckle object every time the property to assign is a dictionary itself.

Let me know how is going,
Gianluca

4 Likes

Hi @iltabe, @teocomi,
Sorry for the super delayed reply! We ended up creating a recursive function, indeed - worked like a charm!
Thanks a lot for the suggestion and the examples :slight_smile:

Here is a code snippet if anyone else is trying to achieve something similar:

import json

props = json.loads(props)

Base = base.__class__

def as_object(d):
    res = Base()
    for k, v in d.items():
        if isinstance(v, dict):
            res[k] = as_object(v)
        elif isinstance(v, list):
            res[k] = [as_object(vi) if isinstance(vi, dict) else vi
                            for vi in v]
        else:
            res[k] = v
    return res

obj = as_object(props)

Cheers!

4 Likes

Hi AlanRynne!
I’ve tested the logic to assign multiple properties for multiple objects, but when i recreate it with the latest nodes im not sure why do i get different result than in your example and what am i doing wrong here :sweat_smile:
Example file:
CreateObjectsByKeyValue (2).gh (10.5 KB)

1 Like

Hey @Mykyta_Onopko!

First of all, welcome to the community! Feel free to Introduce yourself 🙆 to everyone if you haven’t already :wink:

As for your question, I think its working just as expected. The result of the CSO by Key/Value is 2 Speckle objects, each with different properties:

  • One with 2 properties (prop1 and prop2)
  • A second one with 2 properties (prop3 and prop4)

If you expand each of them individually you’ll notice that each object has been correctly created (note that in my example I did expand them this way).

I think the confusion comes from the fact that Expand Speckle Object will expand all properties of all input objects, and will properly assign each output accordingly.

So what you’re seeing in the screenshot bellow is the following:

Since the first object does not have a prop4 (only prop1 and prop2), the branch {0} remains empty.

The same happens if you inspect prop1 or prop2, since the second object has none of those properties branch {1} will remain empty.

Hope that makes sense! :raised_hands:t3:

1 Like

Thank you for your reply, @AlanRynne ! I think its much more clear to me but i still don’t get why the output for 2nd object gets the property same as first one… I thought it should be the mess with data tree, button the screenshot below you can see the structure is the same for both examples, but the output from first group on screenshot for prop 4 is not correct. could be that an issue with the updated component CSO by key/value i use?