Announcing jSwan - easy JSON support for Grasshopper

Excited to announce the release of jSwan, providing JSON Serialization/Deserialization for Grasshopper. It is open source - you can find the source and the documentation here: GitHub - andrewheumann/jSwan: JSON Serialization/Deserialization for Grasshopper 3d

What is JSwan?

JSwan is a set of Grasshopper components for easily working with JSON-formatted data. It’s desiged to work intuitively with Grasshopper’s component logic and data structures.

What is JSON?

According to https://www.w3schools.com/whatis/whatis_json.asp:

JSON stands for J ava S cript O bject N otation

JSON is a lightweight format for storing and transporting data

JSON is often used when data is sent from a server to a web page

JSON is “self-describing” and easy to understand

Here’s an example object, described in JSON:

{
    "name": "John",
    "age": 30,
    "cars": [
        {
            "name": "Ford",
            "models": [
                "Fiesta",
                "Focus",
                "Mustang"
            ]
        },
        {
            "name": "BMW",
            "models": [
                "320",
                "X3",
                "X5"
            ]
        },
        {
            "name": "Fiat",
            "models": [
                "500",
                "Panda"
            ]
        }
    ]
}

How do I use jSwan?

You can compose JSON Objects with the Serialize JSON component, like so:

serialize gif

The components interact intuitively with Data Trees, and the right-click options allow you to tell the component whether to treat data as individual items/objects or as an array.

Deconstructing JSON is even easier, with the Deserialize JSON component:

deserialize gif

The component automatically generates one output for each unique property of the input data. Each instance of the component deserializes one level of nesting at a time, so that you wind up with a data tree perfectly reflecting the structure of the input data.

What would I use this for?

It’s up to you! There are lots of reasons why you might use a JSON format inside grasshopper. Here are a few:

  • Interacting with the web: data from web services or APIs is often received or sent in JSON format
  • Translating Grasshopper / Rhino formatted geometry into a structured format any program can understand (C#, javascript, python, and most other languages have the ability to read and author JSON data, sometimes with the help of third-party libraries.)
  • “Object Oriented Grasshopper” - construct custom object types by encoding them in JSON and build your own reusable clusters that grab their relevant properties, rather than passing around many parallel data streams. For example, rather than passing along a list of panels, a list of their IDs, and a list of their areas or other data, you could construct a single list of panel JSON objects:
{
"id": "P034",
"area": 2.0,
"boundary": [
    {
    "X": 4.0,
    "Y": 0.0,
    "Z": 0.0
    },
    {
    "X": 4.0,
    "Y": 2.0,
    "Z": 0.0
    },
    {
    "X": 3.0,
    "Y": 2.0,
    "Z": 0.0
    },
    {
    "X": 3.0,
    "Y": 0.0,
    "Z": 0.0
    }
]
}

Detailed Features

Serialize JSON

Serialize Component

Create JSON structures from data you feed in. Use the ZUI (Zoomable UI) to add additional properties as needed. The name you give each parameter will be the name of the JSON Property. Each input will correspond to a property. Right click each input to choose between “Item access” (Treat each object in the input list as a single item) and “List Access” (treat the entire list as an array). Note that the execution of this component follows normal grasshopper list matching behavior, so if property values seem to be “attached” to the wrong objects, check your tree structure. The component uses default object serialization, so if you pass simple types like Points and Vectors, they will automatically serialize as objects with X, Y, and Z properties.

The component also has a right-click menu item “Lock Structure,” which will force the component to include null and empty properties in the resulting object rather than omitting them. You can choose “Lock All Serialize Components” to lock all the serialize components in your definition.

Deserialize JSON

Deserialize Component

Extract data from JSON structures you feed in. For each top-level property of the JSON object, it will generate an output. Properties with simple values (numbers, strings, booleans, etc) will simply output the value; those with objects as values will simply spit out the JSON-formatted contents, so you can chain together another component to deconstruct further. Array properties are broken automatically into lists of values or objects. If the topmost JSON object is itself an array, it will generate a single output called “array.”

Outputs are generated automatically from the unique property names in the data. This means if the input data changes, the component itself may change “shape” by adding/removing outputs. To prevent this from happening, right click to “Lock” the structure of the component - this will prevent its structure from changing, and missing properties will come out as empty lists or nulls. You can choose “Lock All Deserialize Components” to lock all the deserialize components in your definition.

If you input a .JSON file path rather than JSON-formatted text, it will automatically read the contents of the file and deserialize that. Be aware that this may moderately affect performance as compared to using a separate ReadFile component!

Serialize Keys and Values

Serialize KV Component

This component allows you to explicitly provide a list of values for the keys and values of a JSON object, rather than editing the param input names as you do with the regular Serialize component.

Serialize KV Example

Deserialize Keys and Values

Desrialize KV Component

This component lets you deconstruct JSON into lists of keys and values, rather than producing a separate output for every property. You can also supply an optional key input to select only certain keys from an object.

Desrialize KV Example

Thanks

Special thanks to Jonatan Schumacher, Leland Jobson, Serena Li, and Brian Ringley for their contributions to this project as users, testers, and contributors!

30 Likes

Thank you Andrew!
It is super useful. I can naw probably translate my models to Three.js with no problems. And push everything to the web.
Plus as you said having one object with all its attributes in one place is great.

4 Likes

This is awesome! Thanks for your work.

2 Likes

Very useful plugin Andrew! Thanks for the free release!

1 Like

Would this be a good way to store Rhino object properties with the goal of generating Bills Of Materials ?
Does it work with blocks ? Nested blocks ?

Shoot! I just added JSON-capability to Pancake without knowing this… :sob:

2 Likes

You may use UserString to deal with Rhino geometry objects.

Hi Keyu,

Yes, that is what I currently use, but usertext is a half-baked feature in Rhino.
In particular, the interface is terrible, not to mention display bugs.

How is Grasshopper used in your workflow? I’ve never used UserString’s interface in Rhino, as I merely take it as an approach to store metadata which can be interacted with Grasshopper, in order to generate a BOM, etc.

We use GH to attach metadata (through usertexts) to existing and GH-generated blocks, and of course read that data for various tasks such as :

  • Provide “real-time” statistics on the current state of the model, related to weight (steel), Volume (wood), and price (mostly for screws, nuts, bols, connection devices,…), many other keys…
  • Check if all the “user-input” values have been filled in.
  • Check if values make sense to report eventual modeling mistakes or bugs
  • Generate the “intrinsic” values for keys such as volume, area
  • Generate the “hybrid” values such as mass (based on the intrinsic “Volume” key, plus the user-input “Material” key)
  • Fill-in the two-level BOM (sub-parts / parts)

Being able to input or read values through Rhino would be appreciated because it gives extra flexibility on top of GH, even with nifty Human UI interfaces.
Only problem : Rhino’s tabs for texts, dots and user text regularly remains completely blank, forcing to close our models (lately, files way over 1 GB), and re-open them.

That’s why I am looking for alternate ways to store metadata.

1 Like

Hi,
I’m a novice on the JSON topic, but I am trying to create a GH definition, that recreates a JSON file, to have parametric control of the inputs of the file. However I’m struggling to create several keys with the same name with different sub keys and values.
I’ve uploaded an image of my GH definition and the JSON file I would like to recreate.

JSON_Building.gh (13.6 KB)

You were nearly there, just a few little adjustments:

  • Don’t use Merge Json — what you really want is to create an array of objects. You can do this by creating a new object, right clicking its input, and then giving it “list access.”
  • After that, we’ll have to strip out the surrounding object, if you need to produce an array — this is a limitation of JSwan that it only ever produces objects. I’ve provided an example of one way to do this. Eventually I should probably add a component or option for this.
  • Watch out for data types — if your JSON structure expects numbers, be sure to pass your panel output through an int or num param so JSwan can see that they should be serialized as numbers instead of strings.

JSON_Building.gh (17.1 KB)

2 Likes

Likes amazing. I am going to learn it. Very detailed tutorial. Thank you, Andrew!

Thanks for the quick reply Andrew. There’s no chance I would have sought that out myself!

Hello @andheum, I’m really interested in your plugin but after installed it does not show any component. I’ve tried manual and with package manager. It’s jSwan deprecated? Is there any alternative to work with JSON files?

My Rhino version is Rh7 SR18

Thanks!

1 Like

One can import the native json module in GHPython, which is simple to use (assuming one knows a bit of Python of course). I use it extensively.

2 Likes

@andheum One question, if jSwan is used in a GH def for HOPS, it changes the format of the output.

This is the desired JSON format. Using the same def as Hops, it looks like this. However, I would need the json output of the first image. Any idea? Thanks.

No idea — it looks like the value is being turned into an array. I think this must be a Hops thing, because jswan has no awareness of hops and wouldn’t change its behavior deliberately. I am unable to test since hops doesn’t support local execution on mac.

Thanks @andheum, true, somehow the item (json file) converts through hops into multiple items that can’t be “flattened”. So Hops is returning something else in this case. @AndyPayne and @stevebaer, this might be interesting to check.