Example #1
0
def jsonify_anm(anm):
    """ Returns a dictionary of json-ified overlay graphs"""
    anm_json = {}
    for overlay_id in anm.overlays():
        NmGraph = anm[overlay_id]._graph.copy()
        for n in NmGraph:
            try:
                del NmGraph.node[n]['id']
            except KeyError:
                pass
        anm_json[overlay_id] = ank_json_dumps(NmGraph)
    return json.dumps(anm_json)
Example #2
0
def jsonify_anm(anm):
    """ Returns a dictionary of json-ified overlay graphs"""
    anm_json = {}
    for overlay_id in anm.overlays():
        NmGraph = anm[overlay_id]._graph.copy()
        for n in NmGraph:
            try:
                del NmGraph.node[n]['id']
            except KeyError:
                pass
        anm_json[overlay_id] = ank_json_dumps(NmGraph)
    return json.dumps(anm_json)
Example #3
0
def rebind_interfaces(anm):
    for overlay_id in anm.overlays():
        overlay = anm[overlay_id]
        #for edge in overlay.edges():
            #unbound_interfaces = edge._interfaces
## map nodes -> node objects, values to integers (not strings)
            #interfaces = {overlay.node(key): val for key, val in unbound_interfaces.items()}
            #edge._interfaces = interfaces # store with remapped node
        for node in overlay.nodes():
            unbound_interfaces = node._interfaces
            if len(unbound_interfaces): # is list if none set
                interfaces = {int(key): val for key, val in unbound_interfaces.items()}
                node._interfaces = interfaces
Example #4
0
def rebind_interfaces(anm):
    for overlay_id in anm.overlays():
        overlay = anm[overlay_id]
        #for edge in overlay.edges():
            #unbound_interfaces = edge._interfaces
## map nodes -> node objects, values to integers (not strings)
            #interfaces = {overlay.node(key): val for key, val in unbound_interfaces.items()}
            #edge._interfaces = interfaces # store with remapped node
        for node in overlay.nodes():
            unbound_interfaces = node._interfaces
            if len(unbound_interfaces): # is list if none set
                interfaces = {int(key): val for key, val in unbound_interfaces.items()}
                node._interfaces = interfaces
Example #5
0
def jsonify_anm_with_graphics(anm):
    """ Returns a dictionary of json-ified overlay graphs, with graphics data appended to each overlay"""
    anm_json = {}
    graphics_graph = anm["graphics"]._graph.copy()
    for overlay_id in anm.overlays():
        OverlayGraph = anm[overlay_id]._graph.copy()


#TODO: only update, don't over write if already set
        for n in OverlayGraph:
            OverlayGraph.node[n].update( {
                'x': graphics_graph.node[n]['x'],
                'y': graphics_graph.node[n]['y'],
                'asn': graphics_graph.node[n]['asn'],
                'device_type': graphics_graph.node[n]['device_type'],
                'device_subtype': graphics_graph.node[n].get('device_subtype'),
                'pop': graphics_graph.node[n].get('pop'),
                })

            try:
                del OverlayGraph.node[n]['id']
            except KeyError:
                pass

#TODO: combine these, and round as necessary
        x = (OverlayGraph.node[n]['x'] for n in OverlayGraph)
        y = (OverlayGraph.node[n]['y'] for n in OverlayGraph)
        try:
            x_min = min(x)
        except ValueError:
            x_min = 0
        try:
            y_min = min(y)
        except ValueError:
            y_min = 0
        for n in OverlayGraph:
            OverlayGraph.node[n]['x'] += - x_min
            OverlayGraph.node[n]['y'] += - y_min

        anm_json[overlay_id] = ank_json_dumps(OverlayGraph)
    return anm_json
Example #6
0
def jsonify_anm_with_graphics(anm, nidb=None):
    """ Returns a dictionary of json-ified overlay graphs, with graphics data appended to each overlay"""
    from collections import defaultdict
    import math
    anm_json = {}
    test_anm_data = {}
    graphics_graph = anm["graphics"]._graph.copy()
    phy_graph = anm["phy"]._graph  # to access ASNs
    """simple layout of deps - more advanced layout could
    export to dot and import to omnigraffle, etc
    """
    g_deps = anm['_dependencies']
    nm_graph = g_deps._graph
    # build tree
    layers = defaultdict(list)
    if len(nm_graph) > 0:
        topo_sort = nx.topological_sort(nm_graph)
        # trim out any nodes with no sucessors

        tree_root = topo_sort[0]
        #Note: topo_sort ensures that once reach node, would have reached its predecessors
        # start at first element after root
        for node in topo_sort:
            preds = nm_graph.predecessors(node)
            if len(preds):
                pred_level = max(nm_graph.node[p].get('level') for p in preds)
            else:
                # a root node
                pred_level = -1  # this node becomes level 0
            level = pred_level + 1
            nm_graph.node[node]['level'] = level
            layers[level].append(node)

            data = nm_graph.node[node]
            data['y'] = 100 * data['level']
            data['device_type'] = "ank_internal"

        MIDPOINT = 50  # assign either side of
        for nodes in layers.values():
            #TODO: since sort is stable, first sort by parent x (avoids zig-zags)
            nodes = sorted(nodes,
                           reverse=True,
                           key=lambda x: nm_graph.degree(x))
            for index, node in enumerate(nodes):
                #TODO: work out why weird offset due to the math.pow *
                #node_x = MIDPOINT  + 125*index * math.pow(-1, index)
                node_x = MIDPOINT + 125 * index
                nm_graph.node[node]['x'] = node_x

    import random
    attribute_cache = defaultdict(dict)
    # the attributes to copy
    # TODO: check behaviour for None if explicitly set
    #TODO: need to check if attribute is set in overlay..... using API
    copy_attrs = ["x", "y", "asn", "label", "device_type", "device_subtype"]
    for node, in_data in phy_graph.nodes(data=True):
        out_data = {
            key: in_data.get(key)
            for key in copy_attrs if key in in_data
        }
        attribute_cache[node].update(out_data)

    # Update for graphics (over-rides phy)
    for node, in_data in graphics_graph.nodes(data=True):
        out_data = {
            key: in_data.get(key)
            for key in copy_attrs if key in in_data
        }
        attribute_cache[node].update(out_data)

        # append label from function
        for node in anm['phy']:
            attribute_cache[node.id]['label'] = str(node)

    for overlay_id in anm.overlays():
        nm_graph = anm[overlay_id]._graph.copy()
        if overlay_id == "_dependencies":
            nm_graph = nx.Graph(
                nm_graph)  #convert to undirected for visual clarify

        for node in nm_graph:
            node_data = dict(attribute_cache.get(node, {}))
            # update with node data from this overlay
            #TODO: check is not None won't clobber specifically set in overlay...
            graph_node_data = nm_graph.node[node]
            overlay_node_data = {
                key: graph_node_data.get(key)
                for key in graph_node_data
            }
            node_data.update(overlay_node_data)

            # check for any non-set properties
            if node_data.get("x") is None:
                new_x = random.randint(0, 800)
                node_data['x'] = new_x
                # store for other graphs to use
                log.debug("Allocated random x %s to node %s in overlay %s" %
                          (new_x, node, overlay_id))
                attribute_cache[node]['x'] = new_x
            if node_data.get("y") is None:
                new_y = random.randint(0, 800)
                node_data['y'] = new_y
                # store for other graphs to use
                attribute_cache[node]['y'] = new_y
                log.debug("Allocated random y %s to node %s in overlay %s" %
                          (new_y, node, overlay_id))

            if node_data.get("label") == node:
                # try from cache
                node_data['label'] = attribute_cache.get(node, {}).get("label")
            if node_data.get("label") is None:
                node_data['label'] = str(node)  # don't need to cache

            # store on graph
            nm_graph.node[node] = node_data

            if nm_graph.is_multigraph():
                for u, v, k in nm_graph.edges(keys=True):
                    # Store key: nx node_link_data ignores it
                    #anm_graph[u][v][k]['_key'] = k
                    pass  # is this needed? as key itself holds no value?

            try:
                del nm_graph.node[node]['id']
            except KeyError:
                pass

            if nidb:
                nidb_graph = nidb.raw_graph()
                if node in nidb:
                    DmNode_data = nidb_graph.node[node]
                    try:
                        #TODO: check why not all nodes have _ports initialised
                        overlay_interfaces = nm_graph.node[node]["_ports"]
                    except KeyError:
                        continue  # skip copying interface data for this node

                    for interface_id in overlay_interfaces.keys():
                        #TODO: use raw_interfaces here
                        try:
                            nidb_interface_id = DmNode_data['_ports'][
                                interface_id]['id']
                        except KeyError:
                            #TODO: check why arrive here - something not initialised?
                            continue
                        nm_graph.node[node]['_ports'][interface_id][
                            'id'] = nidb_interface_id
                        id_brief = shortened_interface(nidb_interface_id)
                        nm_graph.node[node]['_ports'][interface_id][
                            'id_brief'] = id_brief

        anm_json[overlay_id] = ank_json_dumps(nm_graph)
        test_anm_data[overlay_id] = nm_graph

    if nidb:
        test_anm_data['nidb'] = prepare_nidb(nidb)

    result = json.dumps(test_anm_data,
                        cls=AnkEncoder,
                        indent=4,
                        sort_keys=True)
    return result
Example #7
0
def jsonify_anm_with_graphics(anm, nidb=None):
    """ Returns a dictionary of json-ified overlay graphs, with graphics data appended to each overlay"""
    anm_json = {}
    test_anm_data = {}
    graphics_graph = anm["graphics"]._graph.copy()
    for overlay_id in anm.overlays():
        OverlayGraph = anm[overlay_id]._graph.copy()

        #TODO: only update, don't over write if already set
        for n in OverlayGraph:
            OverlayGraph.node[n].update({
                'x':
                graphics_graph.node[n]['x'],
                'y':
                graphics_graph.node[n]['y'],
                'asn':
                graphics_graph.node[n]['asn'],
                'device_type':
                graphics_graph.node[n]['device_type'],
                'device_subtype':
                graphics_graph.node[n].get('device_subtype'),
                'pop':
                graphics_graph.node[n].get('pop'),
            })

            try:
                del OverlayGraph.node[n]['id']
            except KeyError:
                pass

            if nidb:
                nidb_graph = nidb._graph
                if n in nidb:
                    nidb_node_data = nidb_graph.node[n]
                    try:
                        #TODO: check why not all nodes have _interfaces initialised
                        overlay_interfaces = OverlayGraph.node[n][
                            "_interfaces"]
                    except KeyError:
                        continue  # skip copying interface data for this node

                    for interface_id in overlay_interfaces.keys():
                        try:
                            nidb_interface_id = nidb_node_data['_interfaces'][
                                interface_id]['id']
                        except KeyError:
                            #TODO: check why arrive here - something not initialised?
                            continue
                        OverlayGraph.node[n]['_interfaces'][interface_id][
                            'id'] = nidb_interface_id
                        id_brief = shortened_interface(nidb_interface_id)
                        OverlayGraph.node[n]['_interfaces'][interface_id][
                            'id_brief'] = id_brief


#TODO: combine these, and round as necessary
        x = (OverlayGraph.node[n]['x'] for n in OverlayGraph)
        y = (OverlayGraph.node[n]['y'] for n in OverlayGraph)
        try:
            x_min = min(x)
        except ValueError:
            x_min = 0
        try:
            y_min = min(y)
        except ValueError:
            y_min = 0
        for n in OverlayGraph:
            OverlayGraph.node[n]['x'] += -x_min
            OverlayGraph.node[n]['y'] += -y_min

        anm_json[overlay_id] = ank_json_dumps(OverlayGraph)
        test_anm_data[overlay_id] = OverlayGraph

    if nidb:
        test_anm_data['nidb'] = prepare_nidb(nidb)

    result = json.dumps(test_anm_data,
                        cls=AnkEncoder,
                        indent=4,
                        sort_keys=True)
    return result
Example #8
0
def jsonify_anm_with_graphics(anm, nidb = None):
    """ Returns a dictionary of json-ified overlay graphs, with graphics data appended to each overlay"""
    anm_json = {}
    test_anm_data = {}
    graphics_graph = anm["graphics"]._graph.copy()
    phy_graph = anm["phy"]._graph  # to access ASNs

    import random
    from collections import defaultdict
    attribute_cache = defaultdict(dict)
    # the attributes to copy
    # TODO: check behaviour for None if explicitly set
    #TODO: need to check if attribute is set in overlay..... using API
    copy_attrs =  ["x", "y", "asn", "label", "device_type", "device_subtype"]
    for node, in_data in phy_graph.nodes(data=True):
      out_data = {key: in_data.get(key) for key in copy_attrs
      if key in in_data}
      attribute_cache[node].update(out_data)

    # Update for graphics (over-rides phy)
    for node, in_data in graphics_graph.nodes(data=True):
      out_data = {key: in_data.get(key) for key in copy_attrs
      if key in in_data}
      attribute_cache[node].update(out_data)

    for overlay_id in anm.overlays():
        NmGraph = anm[overlay_id]._graph.copy()

        for node in NmGraph:
            node_data = dict(attribute_cache.get(node, {}))
            # update with node data from this overlay
            #TODO: check is not None won't clobber specifically set in overlay...
            graph_node_data = NmGraph.node[node]
            overlay_node_data = {key: graph_node_data.get(key)
                for key in copy_attrs if key in graph_node_data}
            node_data.update(overlay_node_data)

            # check for any non-set properties
            if node_data.get("x") is None:
                new_x = random.randint(0,800)
                node_data['x'] = new_x
                # store for other graphs to use
                log.debug("Allocated random x %s to node %s in overlay %s" %
                    (new_x, node, overlay_id))
                attribute_cache[node]['x'] = new_x
            if node_data.get("y") is None:
                new_y = random.randint(0,800)
                node_data['y'] =new_y
                # store for other graphs to use
                attribute_cache[node]['y'] =new_y
                log.debug("Allocated random y %s to node %s in overlay %s" %
                    (new_y, node, overlay_id))

            if node_data.get("label") is None:
                node_data['label'] = str(node) # don't need to cache

            # store on graph
            NmGraph.node[node] = node_data

            try:
                del NmGraph.node[node]['id']
            except KeyError:
                pass

            if nidb:
                nidb_graph = nidb.raw_graph()
                if node in nidb:
                    DmNode_data = nidb_graph.node[node]
                    try:
                        #TODO: check why not all nodes have _interfaces initialised
                        overlay_interfaces = NmGraph.node[node]["_interfaces"]
                    except KeyError:
                        continue # skip copying interface data for this node

                    for interface_id in overlay_interfaces.keys():
                        try:
                            nidb_interface_id = DmNode_data['_interfaces'][interface_id]['id']
                        except KeyError:
                            #TODO: check why arrive here - something not initialised?
                            continue
                        NmGraph.node[node]['_interfaces'][interface_id]['id'] = nidb_interface_id
                        id_brief = shortened_interface(nidb_interface_id)
                        NmGraph.node[node]['_interfaces'][interface_id]['id_brief'] = id_brief

        anm_json[overlay_id] = ank_json_dumps(NmGraph)
        test_anm_data[overlay_id] = NmGraph


    if nidb:
        test_anm_data['nidb'] = prepare_nidb(nidb)

    result = json.dumps(test_anm_data, cls=AnkEncoder, indent = 4, sort_keys = True)
    return result
Example #9
0
def jsonify_anm_with_graphics(anm, nidb = None):
    """ Returns a dictionary of json-ified overlay graphs, with graphics data appended to each overlay"""
    anm_json = {}
    test_anm_data = {}
    graphics_graph = anm["graphics"]._graph.copy()
    phy_graph = anm["phy"]._graph  # to access ASNs
    for overlay_id in anm.overlays():
        OverlayGraph = anm[overlay_id]._graph.copy()

#TODO: only update, don't over write if already set
        for n in OverlayGraph:
            OverlayGraph.node[n].update( {
                'x': graphics_graph.node[n]['x'],
                'y': graphics_graph.node[n]['y'],
                'asn': graphics_graph.node[n]['asn'],
                'label': graphics_graph.node[n]['label'],
                'device_type': graphics_graph.node[n]['device_type'],
                'device_subtype': graphics_graph.node[n].get('device_subtype'),
                'pop': graphics_graph.node[n].get('pop'),
                })

            if n in phy_graph:
                # use ASN from physical graph
                OverlayGraph.node[n]['asn'] = phy_graph.node[n]['asn']

            try:
                del OverlayGraph.node[n]['id']
            except KeyError:
                pass

            if nidb:
                nidb_graph = nidb._graph
                if n in nidb:
                    nidb_node_data = nidb_graph.node[n]
                    try:
                        #TODO: check why not all nodes have _interfaces initialised
                        overlay_interfaces = OverlayGraph.node[n]["_interfaces"]
                    except KeyError:
                        continue # skip copying interface data for this node

                    for interface_id in overlay_interfaces.keys():
                        try:
                            nidb_interface_id = nidb_node_data['_interfaces'][interface_id]['id']
                        except KeyError:
                            #TODO: check why arrive here - something not initialised?
                            continue
                        OverlayGraph.node[n]['_interfaces'][interface_id]['id'] = nidb_interface_id
                        id_brief = shortened_interface(nidb_interface_id)
                        OverlayGraph.node[n]['_interfaces'][interface_id]['id_brief'] = id_brief

#TODO: combine these, and round as necessary
        x = (OverlayGraph.node[n]['x'] for n in OverlayGraph)
        y = (OverlayGraph.node[n]['y'] for n in OverlayGraph)
        try:
            x_min = min(x)
        except ValueError:
            x_min = 0
        try:
            y_min = min(y)
        except ValueError:
            y_min = 0
        for n in OverlayGraph:
            OverlayGraph.node[n]['x'] += - x_min
            OverlayGraph.node[n]['y'] += - y_min

        anm_json[overlay_id] = ank_json_dumps(OverlayGraph)
        test_anm_data[overlay_id] = OverlayGraph

    if nidb:
        test_anm_data['nidb'] = prepare_nidb(nidb)

    result = json.dumps(test_anm_data, cls=AnkEncoder, indent = 4, sort_keys = True)
    return result
Example #10
0
def jsonify_anm_with_graphics(anm, nidb=None):
    """ Returns a dictionary of json-ified overlay graphs, with graphics data appended to each overlay"""
    from collections import defaultdict
    import math
    anm_json = {}
    test_anm_data = {}
    graphics_graph = anm["graphics"]._graph.copy()
    phy_graph = anm["phy"]._graph  # to access ASNs

    """simple layout of deps - more advanced layout could
    export to dot and import to omnigraffle, etc
    """
    g_deps = anm['_dependencies']
    nm_graph = g_deps._graph
    # build tree
    layers = defaultdict(list)
    nodes_by_layer = {}
    if len(nm_graph) > 0:
        topo_sort = nx.topological_sort(nm_graph)
        # trim out any nodes with no sucessors

        tree_root = topo_sort[0]
        # Note: topo_sort ensures that once reach node, would have reached its predecessors
        # start at first element after root
        for node in topo_sort:
            preds = nm_graph.predecessors(node)
            if len(preds):
                pred_level = max(nm_graph.node[p].get('level') for p in preds)
            else:
                # a root node
                pred_level = -1  # this node becomes level 0
            level = pred_level + 1
            nm_graph.node[node]['level'] = level
            layers[level].append(node)

            data = nm_graph.node[node]
            data['y'] = 100 * data['level']
            data['device_type'] = "ank_internal"

        MIDPOINT = 50  # assign either side of
        for layer, nodes in layers.items():
            # TODO: since sort is stable, first sort by parent x (avoids
            # zig-zags)
            nodes = sorted(nodes, reverse=True,
                           key=lambda x: nm_graph.degree(x))
            for index, node in enumerate(nodes):
                # TODO: work out why weird offset due to the math.pow *
                #node_x = MIDPOINT  + 125*index * math.pow(-1, index)
                node_x = MIDPOINT + 125 * index
                nm_graph.node[node]['x'] = node_x
                nodes_by_layer[node] = layer

    import random
    attribute_cache = defaultdict(dict)
    # the attributes to copy
    # TODO: check behaviour for None if explicitly set
    # TODO: need to check if attribute is set in overlay..... using API
    copy_attrs = ["x", "y", "asn", "label", "device_type", "device_subtype"]
    for node, in_data in phy_graph.nodes(data=True):
        out_data = {key: in_data.get(key) for key in copy_attrs
                    if key in in_data}
        attribute_cache[node].update(out_data)

    # Update for graphics (over-rides phy)
    for node, in_data in graphics_graph.nodes(data=True):
        out_data = {key: in_data.get(key) for key in copy_attrs
                    if key in in_data}
        attribute_cache[node].update(out_data)

        # append label from function
        for node in anm['phy']:
            attribute_cache[node.id]['label'] = str(node)

    overlay_ids = sorted(anm.overlays(),
                         key=lambda x: nodes_by_layer.get(x, 0))

    for overlay_id in overlay_ids:
        nm_graph = anm[overlay_id]._graph.copy()
        if overlay_id == "_dependencies":
            # convert to undirected for visual clarify
            nm_graph = nx.Graph(nm_graph)

        for node in nm_graph:
            node_data = dict(attribute_cache.get(node, {}))
            # update with node data from this overlay
            # TODO: check is not None won't clobber specifically set in
            # overlay...
            graph_node_data = nm_graph.node[node]
            overlay_node_data = {key: graph_node_data.get(key)
                                 for key in graph_node_data}
            node_data.update(overlay_node_data)

            # check for any non-set properties
            if node_data.get("x") is None:
                new_x = random.randint(0, 800)
                node_data['x'] = new_x
                # store for other graphs to use
                log.debug("Allocated random x %s to node %s in overlay %s" %
                          (new_x, node, overlay_id))
                attribute_cache[node]['x'] = new_x
            else:
                # cache for next time, such as vswitch in l2 for l2_bc
                attribute_cache[node]['x'] = node_data['x']
            if node_data.get("y") is None:
                new_y = random.randint(0, 800)
                node_data['y'] = new_y
                # store for other graphs to use
                attribute_cache[node]['y'] = new_y
                log.debug("Allocated random y %s to node %s in overlay %s" %
                          (new_y, node, overlay_id))
            else:
                attribute_cache[node]['y'] = node_data['y']

            # TODO: may want to re-introduce graphics to store cross-layer data for virtual nodes
            # and cache device type and device subtype
            # TODO: catch for each, if node not in cache
            try:
                attribute_cache[node]['device_type'] = node_data['device_type']
            except KeyError:
                pass  # not set
            try:
                attribute_cache[node][
                    'device_subtype'] = node_data['device_subtype']
            except KeyError:
                pass  # not set

            if node_data.get("label") == node:
                # try from cache
                node_data['label'] = attribute_cache.get(node, {}).get("label")
            if node_data.get("label") is None:
                node_data['label'] = str(node)  # don't need to cache

            # store on graph
            nm_graph.node[node] = node_data

            if nm_graph.is_multigraph():
                for u, v, k in nm_graph.edges(keys=True):
                    # Store key: nx node_link_data ignores it
                    #anm_graph[u][v][k]['_key'] = k
                    pass  # is this needed? as key itself holds no value?

            try:
                del nm_graph.node[node]['id']
            except KeyError:
                pass

            if nidb:
                nidb_graph = nidb.raw_graph()
                if node in nidb:
                    DmNode_data = nidb_graph.node[node]
                    try:
                        # TODO: check why not all nodes have _ports initialised
                        overlay_interfaces = nm_graph.node[node]["_ports"]
                    except KeyError:
                        continue  # skip copying interface data for this node

                    for interface_id in overlay_interfaces.keys():
                        # TODO: use raw_interfaces here
                        try:
                            nidb_interface_id = DmNode_data[
                                '_ports'][interface_id]['id']
                        except KeyError:
                            # TODO: check why arrive here - something not
                            # initialised?
                            continue
                        nm_graph.node[node]['_ports'][
                            interface_id]['id'] = nidb_interface_id
                        id_brief = shortened_interface(nidb_interface_id)
                        nm_graph.node[node]['_ports'][
                            interface_id]['id_brief'] = id_brief

        anm_json[overlay_id] = ank_json_dumps(nm_graph)
        test_anm_data[overlay_id] = nm_graph

    if nidb:
        test_anm_data['nidb'] = prepare_nidb(nidb)

    result = json.dumps(
        test_anm_data, cls=AnkEncoder, indent=4, sort_keys=True)
    return result
Example #11
0
def jsonify_anm_with_graphics(anm, nidb = None):
    """ Returns a dictionary of json-ified overlay graphs, with graphics data appended to each overlay"""
    anm_json = {}
    test_anm_data = {}
    graphics_graph = anm["graphics"]._graph.copy()
    phy_graph = anm["phy"]._graph  # to access ASNs
    for overlay_id in anm.overlays():
        OverlayGraph = anm[overlay_id]._graph.copy()

    #TODO: don't regen x,y for each overlay - persist (possibly across all layers?)
    # for speed/clarity, get the graphics data to a dict and then set x,y if not set
    # then read from this

#TODO: only update, don't over write if already set
        for n in OverlayGraph:
            if n in graphics_graph:
                OverlayGraph.node[n].update( {
                'x': graphics_graph.node[n].get('x'),
                'y': graphics_graph.node[n].get('y'),
                'asn': graphics_graph.node[n]['asn'],
                'label': graphics_graph.node[n]['label'],
                'device_type': graphics_graph.node[n]['device_type'],
                'device_subtype': graphics_graph.node[n].get('device_subtype'),
                'pop': graphics_graph.node[n].get('pop'),
                })

                #TODO: if no label set, then use node if
            elif n in phy_graph:
                #TODO: if in phy but x/y not set, then fall through to setting random
                #TODO: tidy by moving x/y to higher up before each overlay
                # try to copy x/y from phy
                OverlayGraph.node[n].update( {
                        'x': phy_graph.node[n].get('x'),
                        'y': phy_graph.node[n].get('y'),
                        'asn': phy_graph.node[n]['asn'],
                        'label': phy_graph.node[n]['label'],
                        'device_type': phy_graph.node[n]['device_type'],
                        'device_subtype': phy_graph.node[n].get('device_subtype'),
                        'pop': phy_graph.node[n].get('pop'),
                })
            else:
                import random
                log.debug("Converting to graphics JSON format: node %s not in graphics overlay" % n)
                #TODO: see if can key off node hash - so doesn't move nodes around
                if OverlayGraph.node[n].get("x") is None:
                    OverlayGraph.node[n]['x'] = random.randint(0,800)
                if OverlayGraph.node[n].get("y") is None:
                    OverlayGraph.node[n]['y'] =random.randint(0,800)
                if OverlayGraph.node[n].get("label") is None:
                    OverlayGraph.node[n]['label'] = n # set to node ID
                if OverlayGraph.node[n].get("device_type") is None:
                    OverlayGraph.node[n]['device_type'] = None # set to node ID


            if n in phy_graph:
                # use ASN from physical graph
                OverlayGraph.node[n]['asn'] = phy_graph.node[n].get("asn")

            try:
                del OverlayGraph.node[n]['id']
            except KeyError:
                pass

            if nidb:
                nidb_graph = nidb._graph
                if n in nidb:
                    nidb_node_data = nidb_graph.node[n]
                    try:
                        #TODO: check why not all nodes have _interfaces initialised
                        overlay_interfaces = OverlayGraph.node[n]["_interfaces"]
                    except KeyError:
                        continue # skip copying interface data for this node

                    for interface_id in overlay_interfaces.keys():
                        try:
                            nidb_interface_id = nidb_node_data['_interfaces'][interface_id]['id']
                        except KeyError:
                            #TODO: check why arrive here - something not initialised?
                            continue
                        OverlayGraph.node[n]['_interfaces'][interface_id]['id'] = nidb_interface_id
                        id_brief = shortened_interface(nidb_interface_id)
                        OverlayGraph.node[n]['_interfaces'][interface_id]['id_brief'] = id_brief

#TODO: combine these, and round as necessary
        x = (OverlayGraph.node[n]['x'] for n in OverlayGraph)
        y = (OverlayGraph.node[n]['y'] for n in OverlayGraph)
        try:
            x_min = min(x)
        except ValueError:
            x_min = 0
        try:
            y_min = min(y)
        except ValueError:
            y_min = 0

        border_offset = 20 # so don't plot right at edge
        for n in OverlayGraph:
            #TODO: do this once per node, rather than each time
            OverlayGraph.node[n]['x'] += - x_min + border_offset
            OverlayGraph.node[n]['y'] += - y_min + border_offset
            #TODO: make scale to graph size: if size is <100 dont apply
            #OverlayGraph.node[n]['x'] = round(OverlayGraph.node[n]['x']/25) * 25
            #OverlayGraph.node[n]['y'] = round(OverlayGraph.node[n]['y']/25) * 25

            # and round to the nearest grid size
            # for now round to nearest 10

        anm_json[overlay_id] = ank_json_dumps(OverlayGraph)
        test_anm_data[overlay_id] = OverlayGraph


    if nidb:
        test_anm_data['nidb'] = prepare_nidb(nidb)

    result = json.dumps(test_anm_data, cls=AnkEncoder, indent = 4, sort_keys = True)
    return result