Skip to content

Json Serialization Updates for Dynamo #7747

Closed

Description

@ikeough

The purpose of this proposal is to define the json graph format for Dynamo graphs. This graph format splits the graph into two parts. The first part represents the topology of the graph using nodes and connectors. The second part contains objects related to the visualization of the graph. Everything not related to describing compute connectivity, or visualizing the graph, will be considered an application concern and will need to be stored elsewhere. An example of this would be Nodes versus Cameras. Nodes are required in the graph to describe function calls, but Cameras are only used by current Dynamo applications to save vector information related to the user's viewpoint when visualizing the scene in 3D.

Motivations

  • One graph definition shared between Dynamo, CoGS/TS, and AVP.
  • The ability to add custom converters to serialize to property sets.
  • Direct serialization of NodeModels. No more Serialize() and Deserialize() methods. We will be able to remove inconsistent xml serialization code. Node authors have used attributes and elements non-discriminantly over the years, resulting in bloated parsing and deserialization code.
  • Refactoring of Dynamo base classes. Properties related to visualization of the graph should live in the view model or the view.
  • Move versioning from Dynamo to the graph. As more systems rely on the shared graph format, it will be necessary to have a version which means something across the entire system. It is possible that this version can also be tied to the design script language, and that bi-directional conversion between DS and the graph is a requirement.

What Has Already Been Done

Additional Questions and Considerations

  • Does the json graph format become Dynamo's one graph format? If so, we will need to edit the proposal below to consider custom nodes.
  • If Port descriptions are not stored in the graph, where are they stored? Is it possible to have shared function meta-data across Dynamo, AVP, CoGS, and TS.
  • One source of truth for port and function descriptions. This would benefit localization.

The Proposed Graph Format

{
  "Id": "f170f3ea-ae94-43c1-af0c-e2fa76ebc725",
  "Name":"My graph",
  "Description":"A compute graph.",
  "Nodes":[
    {
      "Id":"aNode",
      "ConcreteType":"Dynamo.Graph.Nodes.ZeroTouch.DSFunction, DynamoCore",
      "NodeType":"FunctionNode",
      "FunctionSignature":"Autodesk.DesignScript.Geometry.Point.ByCoordinates@double,double,double",
      "VariableInputPorts": true,
      "Inputs":[
        {
          "Id":"aPort",
          "UseLevels":false,
          "SelectedLevel":2,
          "KeepListStructure":false
        }
      ],
      "Outputs":[],
      "Replication":"auto"
    }
  ],
  "Connectors":[
    {
      "Id": "593c497e-08e3-485a-bf5d-1943d87a9c3b",
      "Start": "38727d94-86bd-4db8-b2a3-95baa1ac8a85",
      "End": "54c0f71a-524b-4443-9972-1e433a0dceb4"
    }
  ],
  "Dependencies":[
    "b7d9beae-14a0-485b-b259-27d0861eb165",
    "e1764a07-f1f4-4257-a672-9920cd7acc4a"
  ],
  "Bindings":[],
  "View":{
    "X":0.0,
    "Y":1000.0,
    "Zoom":0.5,
    "NodeViews":[
      {
        "d65016b6-6845-4423-a831-d20cbf7d37d4":{
          "Name":"Point.ByCoordinates",
          "X":0.0,
          "Y":5.0,
          "IsVisible":"true",
          "IsUpstreamVisible":true
        }
      }
    ],
    "Cameras":[],
    "Annotations":[
      {
        "Id": "A group of nodes.",
        "Nodes": [
          "61aa6da7-0f40-4fbd-b600-05e0daf7e70c",
          "6f0d0008-b446-40aa-be41-75fb3b375f39",
          "00fdf5cf-f509-40d0-afbb-e83957b19cf3",
          "3ea93ee6-7419-4e6a-9748-25737de09ff4"
        ]
      }
    ]
  }
}

Proposed Changes

New JSON Graph Format Current JSON Graph Format Updates to Dynamo Comments
Graph
Uuid Uuid Id The unique identifier of the graph.
Name Name The user-defined name of the graph.
LastModified Remove from serialization. The date/time representing the last update of the graph.
LastModifiedBy Remove from serialization. The unique id of the last user who modified the graph.
Description Description A description of the graph.
Nodes Nodes An array of Node objects.
Connectors Connectors An array of Connector objects.
Dependencies Add a Dependencies field to WorkspaceModel`. An array of identifiers of graphs that are used as functions in this graph.
Bindings Bindings Change sessionData to Bindings. An array of base-64 encoded key value pairs which relate call sites in the graph to data in an associated data store
View Adjust serialization logic to optionally serialize workspace view data. An optional object which has properties related to the visualization state of the graph
View
X X Move to WorkspaceViewModel. The x coordinate of the upper left corner of the graph relative to the current viewing frame.
Y Y Move to WorkspaceViewModel. The Y coordinate of the upper left corner of the graph relative to the current viewing frame.
Zoom Zoom Move to WorkspaceViewModel. The scale factor between 0.0 and 1.0 of the graph.
Cameras Cameras Move to WorkspaceViewModel. An array of Camera objects.
Annotations Annotations Move to WorkspaceViewModel. An array of Annotation objects.
NodeViews Adjust serialization logic to optionally serialize node view data. A map of objects, keyed by the node id, which contains coordinates of each node.
NodeView
Name DisplayName Change to Name.
X X Move to NodeViewModel.
Y Y Move to NodeViewModel.
IsVisible IsVisible Move to NodeViewModel.
IsUpstreamVisible IsUpstreamVisible Move to NodeViewModel
Port
Id Uuid The identifier of the port. Id should be unique within the graph.
UseLevels UseLevels A bool which specifies whether the selectedLevel and keepListStructure properties are considered.
Level Level The level, starting from 0 at the leaf nodes, of nested data which is to be extracted at this port.
KeepListStructure ShouldKeepListStructure Rename to KeepListStructure. KeepListStructure is a bool which specifies whether the incoming list topology should be maintained in the final data.
Node
Id Id The identifier of the graph. Id should be unique within the graph.
ConcreteType ConcreteType The location of the function identified by the FunctionSignature property. For .net assemblies used in Dynamo, this will be a fully qualified type name like Dynamo.Graph.Nodes.ZeroTouch.DSFunction, DynamoCore.
NodeType NodeType The node type to be used on the server.
FunctionSignature FunctionSignature The full qualified name of a function, including its parameters. Parameters are required to disambiguate overloaded functions.
Inputs InputPorts Rename to Inputs. An array of port objects.
Outputs OutputPorts Rename to Outputs. An array of port objects.
VariableInputPorts VariableInputPorts A bool which indicates whether the node has a variable number of input ports.
Replication Replication Used to identify the replication strategy used by this node.
Annotation
Id Uuid The identifier of that annotation. Id should be unique within the document.
Nodes SelectedModels Rename to Nodes. An array of unique identifiers of nodes which are referenced by this annotation.

Activity

  1. added this to the 2.0 milestone on Apr 3, 2017
  2. changed the title [-]Json Serialization for Dynamo[/-] [+]Json Serialization Updates for Dynamo[/+] on Apr 6, 2017
  3. ikeough commented on Apr 7, 2017

    @ikeough
    ContributorAuthor

    @kronz I'd like your feedback on the viewData section idea. This separates the graph description required for compute and that for visualization.

  4. gregmarr commented on Apr 11, 2017

    @gregmarr
    Contributor

    We should use the names from the CoGS schema, so they should have initial caps.

  5. radumg commented on Apr 11, 2017

    @radumg
    Collaborator

    Really like this idea - fits in well with all the web-centred work being done on Forge, and with the where we want to take things. I have 2 quick questions :

    Bindings

    Not sure if I understood the bindings one correctly.
    bindings is an array of base-64 encoded key value pairs which relate call sites in the graph to data in an associated data store. This is currently called callSiteData.

    Is this data that Dynamo will use as inputs for specific nodes ? If yes, great!

    If not, it would be good to add such a property to the JSON : the use case I have in mind is a REST service for running Dynamo graphs where you can POST to it everything it needs to run : a .dyn file and any associated data or input values, returning the result (values, JSON or updated data files). Good precedent is Dynamo Studio's web publishing, although i assume that one uploads everything to a server.

    YAML / RAML / Swagger

    It would be great to publish & develop the API definitions in a common & purpose-made format so people can use them in building integrations and apps that interact with Dynamo.

    Any thoughts on this ?

  6. ikeough commented on Apr 12, 2017

    @ikeough
    ContributorAuthor

    @radumg We are building some services internally which will use this graph format. Those services are built using Swagger, so this graph format is actually represented as a JSON schema in the swagger. I'm not very happy with the client code generated by swagger-codegen currently, so for the immediate future, the .net clients (at least) for these services will be written by hand. When those services are available, for external users, they'll still be able to call /ourShinyNewService/swagger.json to get the schema and build clients of their own.

  7. pboyer commented on Apr 13, 2017

    @pboyer
    Contributor

    I do not see why we are storing lastModified or lastModifiedBy data in the file format. This is not, strictly speaking, the responsibility of a graph. On a desktop it would be handled by the file system. On the web, it really depends on the storage system, so it shouldn't be stored here.

  8. pboyer commented on Apr 13, 2017

    @pboyer
    Contributor

    Appending the word Data onto a field of a data serialization format is a tautology. It could be removed with minimal loss in readability.

  9. pboyer commented on Apr 13, 2017

    @pboyer
    Contributor

    Do all of these have to be a uuid? I'm guessing this is largely for historical purposes, but correct me if I'm wrong. Not all systems will generate equally good uuid's, some implementations are hacks or one-off jobs, so you may want to conceive the format in such a way that the responsibilities of the author and the system are explicit.

  10. ikeough commented on Apr 14, 2017

    @ikeough
    ContributorAuthor

    @boyerp Agreed on the "viewData". We could just have "graph" and "view".

    As for the uuids, we should make it clear that we mean this: https://www.iso.org/standard/53416.html

  11. ikeough commented on Apr 14, 2017

    @ikeough
    ContributorAuthor

    We should also provide the required date/time format if we decide to keep any fields which store date/time. I know @Marrg just ran into this with Dynamo's date/time node supporting any date/time format. This needs to be consistent.

  12. QilongTang commented on May 23, 2017

    @QilongTang
    Contributor

    @ikeough Green team discussed the json format today and thinking about the following format. The only difference between this and your proposed format is wrapping everything other than view blob into a graph blob. Let us know if you think it's OK. Also tasks are coming :)

    {
      "graph":{
        "Id": "f170f3ea-ae94-43c1-af0c-e2fa76ebc725",
        "Name":"My graph",
        "Description":"A compute graph.",
        "Nodes":[
          {
            "Id":"aNode",
            "ConcreteType":"Dynamo.Graph.Nodes.ZeroTouch.DSFunction, DynamoCore",
            "NodeType":"FunctionNode",
            "FunctionSignature":"Autodesk.DesignScript.Geometry.Point.ByCoordinates@double,double,double",
            "VariableInputPorts": true,
            "Inputs":[
              {
                "Id":"aPort",
                "UseLevels":false,
                "SelectedLevel":2,
                "KeepListStructure":false
              }
            ],
            "Outputs":[],
            "Replication":"auto"
          }
        ],
        "Connectors":[
          {
            "Id": "593c497e-08e3-485a-bf5d-1943d87a9c3b",
            "Start": "38727d94-86bd-4db8-b2a3-95baa1ac8a85",
            "End": "54c0f71a-524b-4443-9972-1e433a0dceb4"
          }
        ],
        "Dependencies":[
          "b7d9beae-14a0-485b-b259-27d0861eb165",
          "e1764a07-f1f4-4257-a672-9920cd7acc4a"
        ],
        "Bindings":[]
      }
      "View":{
        "X":0.0,
        "Y":1000.0,
        "Zoom":0.5,
        "NodeViews":[
          {
            "d65016b6-6845-4423-a831-d20cbf7d37d4":{
              "Name":"Point.ByCoordinates",
              "X":0.0,
              "Y":5.0,
              "IsVisible":"true",
              "IsUpstreamVisible":true
            }
          }
        ],
        "Cameras":[],
        "Annotations":[
          {
            "Id": "A group of nodes.",
            "Nodes": [
              "61aa6da7-0f40-4fbd-b600-05e0daf7e70c",
              "6f0d0008-b446-40aa-be41-75fb3b375f39",
              "00fdf5cf-f509-40d0-afbb-e83957b19cf3",
              "3ea93ee6-7419-4e6a-9748-25737de09ff4"
            ]
          }
        ]
      }
    }
  13. gregmarr commented on May 23, 2017

    @gregmarr
    Contributor

    Graph is already the name of the object that is represented there. It seems weird to have a Graph object within a Graph object. What is the purpose of this proposed extra layer?

  14. gregmarr commented on May 23, 2017

    @gregmarr
    Contributor

    I could maybe see putting Nodes and Connectors inside a Compute object, as those are the parts needed by the compute component if you want to explicitly call out "compute" vs "view" data, but the ID, Name, and Description aren't actually needed by compute.

  15. 15 remaining items

  16. gregmarr commented on Jun 10, 2017

    @gregmarr
    Contributor

    @mjkkirschner Makes sense. Can you also give me descriptions of IsVisible and IsUpstreamVisible for NodeView? Should Annotation have a Name field?

  17. gregmarr commented on Jun 10, 2017

    @gregmarr
    Contributor

    One more, did we decide that nodes are still UUIDs, or are they free form IDs?

  18. mjkkirschner commented on Jun 10, 2017

    @mjkkirschner
    Member
    • today isVisible reflects the preview state of geometry (is it showing or not in the background preview)
    • I thinkIsUpstreamVisiblereflects if the node outputs its upstream nodes into render packages - this is only useful for watch 3d nodes, and I don't know if it works very well.... I think we could get rid of this from Dynamo in the future.
    • I do not think Annotation has a name, though it has a text field.
    • I proposed nodes just had ids(@pboyer initially suggested this I think) and no one disagreed when I asked in my PR :) - I've added a set of tests that duplicate the serializationTests but with non guid ids for all models except the workspaceModel
  19. gregmarr commented on Jun 10, 2017

    @gregmarr
    Contributor
    • Should we rename IsVisible to something like IsGeometryVisible, PreviewGeometry or ShowGeometry?
    • I knew we agreed on non-uuid for ports, wasn't sure about nodes.
    • Okay, I'll leave upstream out of the schema for now.
  20. mjkkirschner commented on Jun 10, 2017

    @mjkkirschner
    Member

    @gregmarr @ikeough

    • I'm not sure about the isVisible rename... no strong feelings - but that should be straight forward.
    • larger question - does the view block belong in the schema at all?
  21. gregmarr commented on Jun 10, 2017

    @gregmarr
    Contributor

    larger question - does the view block belong in the schema at all?

    Absolutely. The schema should contain exactly those things that every client needs to display the graph.
    Otherwise, every client is going to be inventing their own method of storing it, and no one will be able to display anyone else's graph properly.

  22. QilongTang commented on Jun 16, 2017

    @QilongTang
    Contributor

    Latest schema:

    {
      "Uuid": "a3198e60-91b1-4425-aeac-35b22642af2e",
      "IsCustomNode": false,
      "Description": null,
      "Name": "Home",
      "ElementResolver": {
        "ResolutionMap": {}
      },
      "Nodes": [
        {
          "ConcreteType": "Dynamo.Graph.Nodes.CodeBlockNodeModel, DynamoCore",
          "NodeType": "CodeBlockNode",
          "Code": "x=1;",
          "Id": "a0d3adf8-eda5-47d2-a5e6-4a9bf15f547d",
          "Inputs": [],
          "Outputs": [
            {
              "Id": "e127fbd0-eae5-4d19-be8c-cf0cf434a084",
              "Name": "",
              "Description": "x",
              "Level": 2,
              "UseLevels": false,
              "KeepListStructure": false
            }
          ],
          "Replication": "Disabled",
          "Description": "Allows for DesignScript code to be authored directly"
        }
      ],
      "Connectors": [],
      "Dependencies": [],
      "Bindings": [],
      "View": {
        "Cameras": {
          "EyePosition": "-17,24,50",
          "UpDirection": "0,1,0",
          "LookDirection": "12,-13,-58",
          "Name": "Background Preview"
        },
        "NodeViews": [
          {
            "Id": "a0d3adf8-eda5-47d2-a5e6-4a9bf15f547d",
            "Name": "Code Block",
            "X": 136.0,
            "Y": 247.0,
            "IsVisible": true,
            "IsUpstreamVisible": true
          }
        ],
        "Notes": [
          {
            "Id": "a0a62424-ab53-4b3d-9952-2d876be4e689",
            "X": 269.5,
            "Y": 249.5,
            "Text": "Awesome Note"
          }
        ],
        "Annotations": [
          {
            "Id": "196decf8-2b17-42bf-a9da-f0434030d808",
            "Title": "Dummy",
            "Nodes": [
              "a0d3adf8-eda5-47d2-a5e6-4a9bf15f547d"
            ],
            "Left": 126.0,
            "Top": 194.0,
            "Width": 135.05,
            "Height": 146.0,
            "FontSize": 36.0,
            "InitialTop": 247.0,
            "InitialHeight": 123.0,
            "TextblockHeight": 43.0,
            "Background": "#FFC1D676"
          }
        ],
        "X": 0.0,
        "Y": 0.0,
        "Zoom": 1.0
      }
    }
  23. mjkkirschner commented on Jun 16, 2017

    @mjkkirschner
    Member

    @QilongTang when Notes are serialized they should not have a UUID right? There is a task for serializing them as Annotations - correct?

  24. ramramps commented on Jun 16, 2017

    @ramramps
    Collaborator

    That is on top of the backlog. Not sure when we will visit that task.
    The notes should live inside View block. Do we have a task for it? @QilongTang can you create one if there is not already?

  25. QilongTang commented on Jun 16, 2017

    @QilongTang
    Contributor

    @mjkkirschner @ramramps Yes, specified in https://jira.autodesk.com/browse/QNTM-908, can we solve them together?

  26. ramramps commented on Jun 16, 2017

    @ramramps
    Collaborator

    Moving the notes to view block should be done first. It will help the deserilization. Then we can visit this task and do the serialization / deserialization as specified. Makes sense @QilongTang ?

  27. QilongTang commented on Jun 16, 2017

    @QilongTang
    Contributor

    https://jira.autodesk.com/browse/QNTM-923 and https://jira.autodesk.com/browse/QNTM-908 for moving Notes from graph block into View->Annotation block

  28. radumg commented on Jun 18, 2017

    @radumg
    Collaborator

    Quick question on the schema above : will the "Nodes": [] array also allow specification of an entire graph as an object, for use with graph orchestration when/if this ships ?

    If there is an intention to enable this workflow later on (we absolutely should in my opinion, really need it in practical applications) , would this require the addition of another property at top-level, or does the IsCustomNode property cover it ?
    A graph that would be embedded as a node in another graph would then be something like :

    {
      "Uuid": "772c4d87-44cd-42d2-9971-1c236b98e25c",
      "IsCustomNode": false,
      "IsEmbeddedGraph": true,
      "Description": null,
      "Name": "ChildGraphName",
      "ElementResolver": {},
      "Nodes": [],
      "Notes": [],
      "Connectors": [],
      "Dependencies": [],
      "Bindings": [],
      "View": {}
    }
    

    Let me know if it's off-topic or for another thread.

  29. QilongTang commented on Dec 4, 2019

    @QilongTang
    Contributor

    To those still watching this thread, I am closing this since the team has finished the framework of Json serialization as part of Dynamo 2.0. If you have request or questions about schema, please open new issue or PR.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions