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:
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).
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
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.
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!
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!):
"""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.
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
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)
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
Example file: CreateObjectsByKeyValue (2).gh (10.5 KB)
First of all, welcome to the community! Feel free to Introduce yourself 🙆 to everyone if you haven’t already
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.
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?