question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Model JSON for visual representation

See original GitHub issue

This captures and expands our discussion on Model JSON spec for visual representation and evaluation. The basic idea is that the current spec does not make it easy enough to generate the UI components and the front-end would have to do some tree evaluation and manipulation work. This is an effort to capture and codify the things that will need to be done and how.

This issue is meant to capture the discussion, there is at least one design alternative that needs input.

The main objective is to provide a credible example of NDVI-reclassify-difference calculation that is consistent likely future features.

Model JSON Spec

Model endpoint is going to accept JSON that represent a complete expression tree. The client is responsible for the expression tree and bind its parameters. The client needs to have access to full expression tree in order to show the visual represetnation and to manipulate in response to user actions.

The client is free to add additional tags that make the job of representing the expression tree easier. This tags would be ignored during the expression evaluation.

Endpoints

The request pattern will be something like this:

  • Build expression tree but sourcing existing models GET: .../library/?q=NDVI
    GET: .../library/{model_id}

  • Register expression with the app POST: .../model_run -> { <run_id>, <validation_message> }

  • View the model on a map GET: .../model_run/{run_id}/{z}/{x}/{y}.png

  • View intermidate stages GET: .../model_run/{run_id}/tag/{tag_id}/{z}/{x}/{y}.png

  • Update the model or parameters PATCH: .../model_run -> { <run_id>, <validation_message> }

Parameters

Parameters need to be fully specified at each use-site. Information for display of the expression can be gathered by aggregating over the tree. Parameters may be changed by tree substitution.

Variable tag has to hold information for several contexts:

  • type: What kind of thing does this veriable specify
  • mosaic, scene, band: Identifying tags for the variable type
  • label: Name of the original parameter in the model
  • id: Identity/Name of the parameter in this model

id and label are different because a parameter in the model being specified maybe be reused in several model templates.

We need id so we can replace all references to a single variable during tree traversal.

We need to keep label because as we drill down the model we need that name to help make sense of the paramter usage in the subtree (ex: When looking at NDVI subtree knowing that given mosaic UUID corresponds to red parameter in NDVI)

{
    "id": "LC8_0_NIR",
    "name": "nir",
    "type": "raster",
    "mosaic": "123e4567-e89b-12d3-a456-426655440001",
    "band": 4
}

Parameter types

This list will be expanded as we add more operations but intially parameters types me be:

  • raster
  • class-breaks
  • polygon
  • double
  • int

Parameter identies

There may be multiple ways to satisfy a parameter of a given type, like raster. For instance a raster tile may secured from:

  • project mosaic
  • A single scene
  • A saved model run

When this is possible the additional tags will be used to source the raster tile.

Source a raster tile from project mosaic:

{
   "id": "LC8_0_NIR",
   "name": "nir",
    "type": "raster",
    "mosaic": "123e4567-e89b-12d3-a456-426655440000",
    "band": 4
}
// source a raster tile from a scene
{
    "id": "LC8_0_NIR",
    "name": "nir",
    "type": "raster",
    "scene": "123e4567-e89b-12d3-a456-426655440000",
    "band": 4
}
// source a raster tile from a scene
{
    "id": "LC8_0_NIR",
    "name": "nir",
    "type": "raster",
    "modelRun": "123e4567-e89b-12d3-a456-426655440000",
}

Expression Structure

The expression structure will be composed of nested apply blocks that represent map algebra operation. Basic map-algebra operations will always be pre-defined (ex: “+”, “-”, “/”)

{ 
    "apply": "-", 
    "args": [ 
        { 
            "type": "raster",
            "mosaic": "123e4567-e89b-12d3-a456-426655440000"
        }, 
        {
            "type": "raster",
            "mosaic": "123e4567-e89b-12d3-a456-426655440000"
        } 
    ]
}

Model Library

Model library will have a list of model templates that can be combined together. The models in the model library will have the parameters with types defined but they may not have identifying information.

When a model template is inserted into the expression tree it should retain a reference to template record so it can be referenced and shown in the visual representation.

Opaque models

A model may be opaque either because it is private or because it does not have a JSON expression representation.

When this happens the model will be expressed as a model operation with an id tag that references the model.

Secret version of reclassify:

{ 
    "apply": "model",
    "id": "123e4567-e89b-12d3-a456-426655441111",
    "args": {
        "breaks": {
            "type": "class-breaks"
        },
        "raster": {
        "name": "nir",
         "type": "raster"
    }
    }
}

Named parameters

Some operations require non-raster parameter. For instance the reclassify operation requires breaks parameter. breaks corresponds to BreakMap type in GeoTrellis and specifies where the class boundaries exist and how they are to be handled. (ex: less than, exact match, greater than).

This illustrates:

  • We need named parameters to differentiate different param types
  • We need to represent and parse corresponding complex object represetnations
{
    "apply": "reclassify",
    "args": {
        "breaks": {
            "type": "class-breaks",
            "boundaryType": "lessThan",
            "classMap": [[3.3, 0], [5.0, 1], [6.1], 2]
        },
        "raster": {
            "name": "nir",
            "type": "raster",
            "mosaic": "123e4567-e89b-12d3-a456-426655440001",
            "band": 4
        }
    }
}

args may either be a dictionary or an array, depending on the operation.

As a convention we can say when an operation requires one more parameter of a single type where only the order matters, like raster addition, the args list will be an array. Alternativly if the operations arguments are heterogenious or have specific semantic meanings the args will be a dictionary.

Expression Inspection

A critical feature of the model endpoints is to evaluate and display a subtree of the expression. In order for this to be possible the client may insert tag element in any of apply nodes. It is up to the client to insure that these tags are unique and possibly meaningful.

The endpoint will provide a way to inspect the expression at the level of a given tag by providing an endpoint like: .../model_run/<model_id>/tag/<tag_id>/{z}/{x}/{y}

Color Maps

Each apply element may contain colormap attribute the defines how to render that operation when requested.

NDVI Reclassify Difference

{
    "apply": "-",
    "args": [
        {
            "id": "reclassify_uuid",
            "apply": "reclassify",
            "args": {
                "breaks": {                 
                    "type": "class-breaks",
                    "id": "classes-1",
                    "boundaryType": "lessThan",
                    "classMap": [[3.3, 0], [5.0, 1], [6.1, 2]]
                },             
                "raster": {
                    "id": "<ndvi_model_uuid>",
                    "display": "NDVI Time 0",
                    "tag": "1",
                    "apply": "/", "args": [
                        { "apply": "-", "args": [
                            {
                                "type": "layer",
                                "label": "red",
                                "project": "123e4567-e89b-12d3-a456-426655440000",
                                "band": 3
                            },
                            {
                                "type": "layer",
                                "label": "nir",
                                "project": "123e4567-e89b-12d3-a456-426655440000",
                                "band": 4
                            }
                        ]
                        },
                        { "apply": "+", "args": [
                            {
                                "type": "layer",
                                "label": "red",
                                "project": "123e4567-e89b-12d3-a456-426655440000",
                                "band": 3
                            },
                            {
                                "type": "layer",
                                "label": "nir",
                                "project": "123e4567-e89b-12d3-a456-426655440000",
                                "band": 4
                            }
                        ]}
                    ]
                }
            }
        },
        {
            "id": "reclassify_uuid",
            "apply": "reclassify",
            "args": {
                "breaks": {
                    "type": "class-breaks",
                    "id": "classes-1",
                    "boundaryType": "lessThan",
                    "classMap": [[3.3, 0], [5.0, 1], [6.1, 2]]
                },
                "raster": {
                    "id": "<ndvi_model_uuid>",
                    "display": "NDVI Time 1",
                    "tag": "2",
                    "apply": "/", "args": [
                        { "apply": "-", "args": [
                            {
                                "type": "layer",
                                "label": "red",
                                "project": "123e4567-e89b-12d3-a456-426655440001",
                                "band": 3
                            },
                            {
                                "type": "layer",
                                "label": "nir",
                                "project": "123e4567-e89b-12d3-a456-426655440001",
                                "band": 4
                            }
                        ]
                        },
                        { "apply": "+", "args": [
                            {
                                "type": "layer",
                                "label": "red",
                                "project": "123e4567-e89b-12d3-a456-426655440001",
                                "band": 3
                            },
                            {
                                "type": "layer",
                                "label": "nir",
                                "project": "123e4567-e89b-12d3-a456-426655440001",
                                "band": 4
                            }
                        ]}
                    ]
                }
            }
        }
    ]
}

Alternative Parameter Usage

Above stated parameter expression is most flexible as it places full burden of parameter tracking on they who assemble and manipulate the expression tree, allowing for various strategies to do that.

However, it may be made more redaundant by using what we know about the parameter usage.

Given: A model template must specify all of its parameters and their types

  • no other variable references are allowed in that sub-tree
  • we can bind all the values at the root of that sub-tree

In this case binding is either:

  • Bind a variable to a concrete value
  • Bind a variable to a parameter above the tree

Bind to concrete

{
    "name": "nir",
    "type": "raster",
    "mosaic": "123e4567-e89b-12d3-a456-426655440001",
    "band": 4
}

Bind to another parameter

{
    "name": "nir",
    "type": "raster",   
    "ref": "LC8_0_nir"
}

In this form the model from the model library will have a params elemnt that applies to it. When the model template is inserted into some expression tree the params element continues to exist at that level of the tree but now must be bound.

This form is more consistent with opaque models, where lacking the model body only parameters must be specified.

This form is not significantly harder to parse at evaluation time. The choice should be based on ease of manipulation for UI representation.

Dependency Re-Use

This yet part of the spec

Lets assume there is an operation that we must re-use and it is expensive. With definition above there is no explicit way to state the re-use. At most it is possible to duplicate an subtree.

An strucutre similar to PDAL pipeline can be useful here: http://www.pdal.io/pipeline.html The basic structure is to define stages with explicit inter-dependency. Resolving these dependencies would produce the full tree.

[
    {
        "apply": "costditance",
        "args": { "..." },
        "ref": "CD"
    },
    {
        "apply": "-",
        "args": [
            {
                "apply": "focal-avg",
                "args": { "raster": "CD", "neighborhood": 4 }
            },            
            {
                "apply": "focal-slope",
                "args": { "raster": "CD", "neighborhood": 6 }
            }
        ]
    }
]

Issue Analytics

  • State:closed
  • Created 7 years ago
  • Comments:5 (5 by maintainers)

github_iconTop GitHub Comments

1reaction
notthatbreezycommented, Feb 14, 2017

In case you missed it, this is the PR that implemented the JSON interpretation on the front-end in case it helps to see the adaptations necessary there.

0reactions
jmorrison1847commented, Jun 27, 2017

Can this be closed? MAML lives.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Understanding JSON Modeling Simplified 101 - Hevo Data
In this article, you will learn about JSON Modeling and how it's ... Data Modeling is a process of generating a visual representation...
Read more >
Visualize JSON Data Graph - Code Beautify
This JSON Graph Visualizer helps you to Chart JSON data in Graph and helps to drill down the json data. What can you...
Read more >
5 Reasons to Choose a Graphical JSON Schema Editor - Altova
There are several advantages to using a full-featured, graphical JSON Schema editor and generator instead of a text-only JSON editor.
Read more >
model | A visual representation of the NIEM data model
A visual representation of the NIEM data model; JSON Schema is coming soon.
Read more >
A visual representation of the NIEM data model - GitHub
A visual representation of the NIEM data model; JSON Schema is coming soon - GitHub - NIEM/model: A visual representation of the NIEM...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found