# Cytoscape Elements

## Element Declaration

Each element is defined by a dictionary declaring its purpose and describing its properties. Usually, you specify what group the element belongs to (i.e., if it's a node or an edge), indicate what position you want to give to your element (if it's a node), or what data it contains. In fact, the `data` and `position` keys are themselves mapped to dictionaries, where each item specify an aspect of the data or position.

In the case of `data`, the typical keys fed to the dictionaries are:

- `id`: The index of the element, useful when you want to reference it
- `label`: The name associated with the element if you wish to display it

If your element is an edge, the following keys are required in your data dictionary:

- `source`: The `id` of the source node, which is where the edge starts
- `target`: The `id` of the target node, where the edge ends

The `position` dictionary takes as items the `x` and `y` position of the node. If you use any other layout than `preset`, or if the element is an edge, the position item will be ignored.

If we want a graph with two nodes, and an edge connecting those two nodes, we effectively need three of those element dictionaries, grouped as a list:

    using Dash, DashCytoscape

    app = dash()

    app.layout = cyto_cytoscape(
        id="cytoscape-elements-basic",
        layout=Dict("name" => "preset"),
        style=Dict("width" => "100%", "height" => "400px"),
        elements=[
            # The nodes elements
            Dict("data" => Dict("id" => "one", "label" => "Node 1"),
             "position" => Dict("x" => 50, "y" => 50)),
            Dict("data" => Dict("id" => "two", "label" => "Node 2"),
             "position" => Dict("x" => 200, "y" => 200)),

            # The edge elements
            Dict("data" => Dict("source" => "one", "target" => "two", "label" => "Node 1 to 2"))
        ]
    )

    run_server(app, "0.0.0.0", debug=true)

Notice that we also need to specify the `id`, the `layout`, and the `style` of Cytoscape. The `id` parameter is needed for assigning callbacks, `style` lets you specify the CSS style of the component (similarly to core components), and layout tells you how to arrange your graph. It is described in depth in part 2, so all you need to know is that `'preset'` will organize the nodes according to the positions you specified.

The official Cytoscape.js documentation nicely outlines the JSON format for declaring elements.

## Boolean Properties

In addition to the properties presented above, the element dictionary can also accept boolean items that specify its state. We extend the previous example in the following way:

    using Dash, DashCytoscape
    app = dash()

    app.layout = cyto_cytoscape(
        id="cytoscape-elements-boolean",
        layout=Dict("name" =>  "preset"),
        style=Dict("width" =>  "100%", "height" =>  "400px"),
        elements=[
            Dict(
                "data" =>  Dict("id" =>  "one", "label" =>  "Locked"),
                "position" =>  Dict("x" =>  75, "y" =>  75),
                "locked" =>  true
            ),
            Dict(
                "data" =>  Dict("id" =>  "two", "label" =>  "Selected"),
                "position" =>  Dict("x" =>  75, "y" =>  200),
                "selected" =>  true
            ),
            Dict(
                "data" =>  Dict("id" =>  "three", "label" =>  "Not Selectable"),
                "position" =>  Dict("x" =>  200, "y" =>  75),
                "selectable" =>  false
            ),
            Dict(
                "data" =>  Dict("id" =>  "four", "label" =>  "Not grabbable"),
                "position" =>  Dict("x" =>  200, "y" =>  200),
                "grabbable" =>  false
            ),
            Dict("data" =>  Dict("source" =>  "one", "target" =>  "two")),
            Dict("data" =>  Dict("source" =>  "two", "target" =>  "three")),
            Dict("data" =>  Dict("source" =>  "three", "target" =>  "four")),
            Dict("data" =>  Dict("source" =>  "two", "target" =>  "four")),
        ]
    )

    run_server(app, "0.0.0.0", debug=true)

> Note that those boolean properties can be overwritten by certain Cytoscape parameters such as `autoungrabify` or `autounselectify`. Please refer to the reference for more information.

## Classes

Similarly to CSS classes, element classes are used to style groups of elements using a selector. We modify the previous example by giving the elements a class or multiple classes (separated by a space), and define a stylesheet that modifies the elements based on those classes.

    using Dash, DashCytoscape

    app = dash()

    my_stylesheet = [
        # Group selectors
        Dict(
            "selector" =>  "node",
            "style" =>  Dict(
                "content" =>  "data(label)"
            )
        ),

        # Class selectors
        Dict(
            "selector" =>  ".red",
            "style" =>  Dict(
                "background-color" =>  "red",
                "line-color" =>  "red"
            )
        ),
        Dict(
            "selector" =>  ".triangle",
            "style" =>  Dict(
                "shape" =>  "triangle"
            )
        )
    ]

    app.layout = cyto_cytoscape(
        id="cytoscape-elements-classes",
        layout=Dict("name" =>  "preset"),
        style=Dict("width" =>  "100%", "height" =>  "400px"),
        stylesheet=my_stylesheet,
        elements=[
            Dict(
                "data" =>  Dict("id" =>  "one", "label" =>  "Modified Color"),
                "position" =>  Dict("x" =>  75, "y" =>  75),
                "classes" =>  "red" # Single class
            ),
            Dict(
                "data" =>  Dict("id" =>  "two", "label" =>  "Modified Shape"),
                "position" =>  Dict("x" =>  75, "y" =>  200),
                "classes" =>  "triangle" # Single class
            ),
            Dict(
                "data" =>  Dict("id" =>  "three", "label" =>  "Both Modified"),
                "position" =>  Dict("x" =>  200, "y" =>  75),
                "classes" =>  "red triangle" # Multiple classes
            ),
            Dict(
                "data" =>  Dict("id" =>  "four", "label" =>  "Regular"),
                "position" =>  Dict("x" =>  200, "y" =>  200)
            ),
            Dict("data" =>  Dict("source" =>  "one", "target" =>  "two"), "classes" =>  "red"),
            Dict("data" =>  Dict("source" =>  "two", "target" =>  "three")),
            Dict("data" =>  Dict("source" =>  "three", "target" =>  "four"), "classes" =>  "red"),
            Dict("data" =>  Dict("source" =>  "two", "target" =>  "four")),
        ]
    )

    run_server(app, "0.0.0.0", debug=true)

> The stylesheet parameter will be described in depth in part 3 of this guide. We will show extensive examples of using selectors to style groups, classes, and data values. Expand below if you still want to take a look at the stylesheet used previously.

View the Stylesheet

    my_stylesheet = [
        # Group selectors
        Dict(
            "selector" =>  "node",
            "style" =>  Dict(
                "content" =>  "data(label)"
            )
        ),

        # Class selectors
        Dict(
            "selector" =>  ".red",
            "style" =>  Dict(
                "background-color" =>  "red",
                "line-color" =>  "red"
            )
        ),
        Dict(
            "selector" =>  ".triangle",
            "style" =>  Dict(
                "shape" =>  "triangle"
            )
        )
    ]

## Compound Nodes

A concept introduced in Cytoscape.js, compound nodes are nodes that contain (parent), or are contained (child) inside another node. A parent node does not have have a position nor a size, since those values are automatically calculated based on how the children nodes are configured.

Here is the example of an app using compound nodes:

    using Dash, DashCytoscape

    app = dash()

    app.layout = html_div([
        cyto_cytoscape(
            id="cytoscape-compound",
            layout=Dict("name" =>  "preset"),
            style=Dict("width" =>  "100%", "height" =>  "450px"),
            stylesheet=[
                Dict(
                    "selector" =>  "node",
                    "style" =>  Dict("content" =>  "data(label)")
                ),
                Dict(
                    "selector" =>  ".countries",
                    "style" =>  Dict("width" =>  5)
                ),
                Dict(
                    "selector" =>  ".cities",
                    "style" =>  Dict("line-style" =>  "dashed")
                )
            ],
            elements=[
                # Parent Nodes
                Dict(
                    "data" =>  Dict("id" =>  "us", "label" =>  "United States")
                ),
                Dict(
                    "data" =>  Dict("id" =>  "can", "label" =>  "Canada")
                ),

                # Children Nodes
                Dict(
                    "data" =>  Dict("id" =>  "nyc", "label" =>  "New York", "parent" =>  "us"),
                    "position" =>  Dict("x" =>  100, "y" =>  100)
                ),
                Dict(
                    "data" =>  Dict("id" =>  "sf", "label" =>  "San Francisco", "parent" =>  "us"),
                    "position" =>  Dict("x" =>  100, "y" =>  200)
                ),
                Dict(
                    "data" =>  Dict("id" =>  "mtl", "label" =>  "Montreal", "parent" =>  "can"),
                    "position" =>  Dict("x" =>  400, "y" =>  100)
                ),

                # Edges
                Dict(
                    "data" =>  Dict("source" =>  "can", "target" =>  "us"),
                    "classes" =>  "countries"
                ),
                Dict(
                    "data" =>  Dict("source" =>  "nyc", "target" =>  "sf"),
                    "classes" =>  "cities"
                ),
                Dict(
                    "data" =>  Dict("source" =>  "sf", "target" =>  "mtl"),
                    "classes" =>  "cities"
                )
            ]
        )
    ])

    run_server(app, "0.0.0.0", debug=true)