【问题标题】:Not able to create graph links/edges using networkx and d3无法使用 networkx 和 d3 创建图形链接/边
【发布时间】:2019-11-18 17:42:43
【问题描述】:

我正在尝试从 rest api 调用创建简单的节点和边图......到目前为止能够获取节点,将其作为 json 转储并发送到 d3 进行可视化。 这里的问题是我无法绘制边缘或链接。它在下面给我一个错误

e = (link['link']['destination']['node']['node-id'], link['link']['source']['node']['node-id'])
TypeError: 'int' object has no attribute '__getitem__'

这是从 ODL REST API 调用的节点和链接的详细信息

Nodes List:
Node ID -  openflow:1
Node ID -  host:00:00:00:00:00:01
Node ID -  openflow:2
Node ID -  host:00:00:00:00:00:02

Links List:
Link ID -  host:00:00:00:00:00:01/openflow:1:1
Link ID -  openflow:2:1/host:00:00:00:00:00:02
Link ID -  openflow:1:2
Link ID -  openflow:2:2
Link ID -  openflow:1:1/host:00:00:00:00:00:01
Link ID -  host:00:00:00:00:00:02/openflow:2:1

这是来自 API 的详细信息调用

{
  u'network-topology': {
    u'topology': [
      {
        u'node': [
          {
            u'opendaylight-topology-inventory:inventory-node-ref': u"/opendaylight-inventory:nodes/opendaylight-inventory:node[opendaylight-inventory:id='openflow:1']",
            u'node-id': u'openflow:1',
            u'termination-point': [
              {
                u'opendaylight-topology-inventory:inventory-node-connector-ref': u"/opendaylight-inventory:nodes/opendaylight-inventory:node[opendaylight-inventory:id='openflow:1']/opendaylight-inventory:node-connector[opendaylight-inventory:id='openflow:1:2']",
                u'tp-id': u'openflow:1:2'
              },
              {
                u'opendaylight-topology-inventory:inventory-node-connector-ref': u"/opendaylight-inventory:nodes/opendaylight-inventory:node[opendaylight-inventory:id='openflow:1']/opendaylight-inventory:node-connector[opendaylight-inventory:id='openflow:1:1']",
                u'tp-id': u'openflow:1:1'
              },
              {
                u'opendaylight-topology-inventory:inventory-node-connector-ref': u"/opendaylight-inventory:nodes/opendaylight-inventory:node[opendaylight-inventory:id='openflow:1']/opendaylight-inventory:node-connector[opendaylight-inventory:id='openflow:1:LOCAL']",
                u'tp-id': u'openflow:1:LOCAL'
              }
            ]
          },
          {
            u'host-tracker-service:addresses': [
              {
                u'first-seen': 1562655393902,
                u'ip': u'10.0.0.1',
                u'mac': u'00:00:00:00:00:01',
                u'id': 6,
                u'last-seen': 1562655393902
              }
            ],
            u'host-tracker-service:id': u'00:00:00:00:00:01',
            u'host-tracker-service:attachment-points': [
              {
                u'active': True,
                u'corresponding-tp': u'host:00:00:00:00:00:01',
                u'tp-id': u'openflow:1:1'
              }
            ],
            u'node-id': u'host:00:00:00:00:00:01',
            u'termination-point': [
              {
                u'tp-id': u'host:00:00:00:00:00:01'
              }
            ]
          },
          {
            u'opendaylight-topology-inventory:inventory-node-ref': u"/opendaylight-inventory:nodes/opendaylight-inventory:node[opendaylight-inventory:id='openflow:2']",
            u'node-id': u'openflow:2',
            u'termination-point': [
              {
                u'opendaylight-topology-inventory:inventory-node-connector-ref': u"/opendaylight-inventory:nodes/opendaylight-inventory:node[opendaylight-inventory:id='openflow:2']/opendaylight-inventory:node-connector[opendaylight-inventory:id='openflow:2:LOCAL']",
                u'tp-id': u'openflow:2:LOCAL'
              },
              {
                u'opendaylight-topology-inventory:inventory-node-connector-ref': u"/opendaylight-inventory:nodes/opendaylight-inventory:node[opendaylight-inventory:id='openflow:2']/opendaylight-inventory:node-connector[opendaylight-inventory:id='openflow:2:1']",
                u'tp-id': u'openflow:2:1'
              },
              {
                u'opendaylight-topology-inventory:inventory-node-connector-ref': u"/opendaylight-inventory:nodes/opendaylight-inventory:node[opendaylight-inventory:id='openflow:2']/opendaylight-inventory:node-connector[opendaylight-inventory:id='openflow:2:2']",
                u'tp-id': u'openflow:2:2'
              }
            ]
          },
          {
            u'host-tracker-service:addresses': [
              {
                u'first-seen': 1562655393906,
                u'ip': u'10.0.0.2',
                u'mac': u'00:00:00:00:00:02',
                u'id': 7,
                u'last-seen': 1562655393906
              }
            ],
            u'host-tracker-service:id': u'00:00:00:00:00:02',
            u'host-tracker-service:attachment-points': [
              {
                u'active': True,
                u'corresponding-tp': u'host:00:00:00:00:00:02',
                u'tp-id': u'openflow:2:1'
              }
            ],
            u'node-id': u'host:00:00:00:00:00:02',
            u'termination-point': [
              {
                u'tp-id': u'host:00:00:00:00:00:02'
              }
            ]
          }
        ],
        u'link': [
          {
            u'link-id': u'host:00:00:00:00:00:01/openflow:1:1',
            u'destination': {
              u'dest-node': u'openflow:1',
              u'dest-tp': u'openflow:1:1'
            },
            u'source': {
              u'source-tp': u'host:00:00:00:00:00:01',
              u'source-node': u'host:00:00:00:00:00:01'
            }
          },
          {
            u'link-id': u'openflow:2:1/host:00:00:00:00:00:02',
            u'destination': {
              u'dest-node': u'host:00:00:00:00:00:02',
              u'dest-tp': u'host:00:00:00:00:00:02'
            },
            u'source': {
              u'source-tp': u'openflow:2:1',
              u'source-node': u'openflow:2'
            }
          },
          {
            u'link-id': u'openflow:1:2',
            u'destination': {
              u'dest-node': u'openflow:2',
              u'dest-tp': u'openflow:2:2'
            },
            u'source': {
              u'source-tp': u'openflow:1:2',
              u'source-node': u'openflow:1'
            }
          },
          {
            u'link-id': u'openflow:2:2',
            u'destination': {
              u'dest-node': u'openflow:1',
              u'dest-tp': u'openflow:1:2'
            },
            u'source': {
              u'source-tp': u'openflow:2:2',
              u'source-node': u'openflow:2'
            }
          },
          {
            u'link-id': u'openflow:1:1/host:00:00:00:00:00:01',
            u'destination': {
              u'dest-node': u'host:00:00:00:00:00:01',
              u'dest-tp': u'host:00:00:00:00:00:01'
            },
            u'source': {
              u'source-tp': u'openflow:1:1',
              u'source-node': u'openflow:1'
            }
          },
          {
            u'link-id': u'host:00:00:00:00:00:02/openflow:2:1',
            u'destination': {
              u'dest-node': u'openflow:2',
              u'dest-tp': u'openflow:2:1'
            },
            u'source': {
              u'source-tp': u'host:00:00:00:00:00:02',
              u'source-node': u'host:00:00:00:00:00:02'
            }
          }
        ],
        u'topology-id': u'flow:1'
      }
    ]
  }
}

这是我测试的代码,它只能获取节点但不能获取链接/边...

# get nodes
resp, content = h.request(url, "GET")
nodeData = json.loads(content)
topology = nodeData['network-topology']['topology'][0]
print "Nodes List:"
for i in range(len(topology['node'])):
    print "Node ID - ", topology['node'][i]['node-id']
    i += 1

# Get links/edges
resp, content = h.request(url, "GET")
linkData = json.loads(content)
topology = linkData['network-topology']['topology'][0]
print "Links List:"
for i in range(len(topology['link'])):
    print "Link ID - ", topology['link'][i]['link-id']
    i += 1


# Add nodes and links into graph
graph = nx.Graph()
for node in range(len(topology['node'])):
    graph.add_node(topology['node'][node]['node-id'])
for link in range(len(topology['link'])):
    e = (link['link']['destination']['node']['node-id'], link['link']['source']['node']['node-id'])
    graph.add_edge(*e)


print "Graph Nodes:"
print graph.nodes()
print "Graph Links:"
print graph.links()

# write json formatted data to use in visualization
d = json_graph.node_link_data(graph)
json.dump(d, open('topo.json','w'))
print('Wrote node-link JSON data')

我尝试通过删除与链接/边缘相关的代码并保留节点并且没有问题..我可以在 topo.json 中获取节点的详细信息..但是当我为链接添加图表时我遇到了问题

这里的问题是我无法绘制边缘或链接。它在下面给我一个错误

e = (link['link']['destination']['node']['node-id'], link['link']['source']['node']['node-id'])
TypeError: 'int' object has no attribute '__getitem__'

我只是不知道如何解决它...在这里感谢专家的建议和帮助..谢谢

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ @

我在下面修改但得到不同的错误 TypeError: string indices must be integers

# Get links/edges
resp, content = h.request(url, "GET")
linkData = json.loads(content)
a = linkData['network-topology']['topology'][0]
print a

# Add links into graph
graph = nx.Graph()
for link in a:
    e = (link['link']['destination']['node']['node-id'], link['link']['source']['node']['node-id'])
    graph.add_edge(*e)

打印上面给出下面的输出

{
  u'node': [
    {
      u'opendaylight-topology-inventory:inventory-node-ref': u"/opendaylight-inventory:nodes/opendaylight-inventory:node[opendaylight-inventory:id='openflow:1']",
      u'node-id': u'openflow:1',
      u'termination-point': [
        {
          u'opendaylight-topology-inventory:inventory-node-connector-ref': u"/opendaylight-inventory:nodes/opendaylight-inventory:node[opendaylight-inventory:id='openflow:1']/opendaylight-inventory:node-connector[opendaylight-inventory:id='openflow:1:2']",
          u'tp-id': u'openflow:1:2'
        },
        {
          u'opendaylight-topology-inventory:inventory-node-connector-ref': u"/opendaylight-inventory:nodes/opendaylight-inventory:node[opendaylight-inventory:id='openflow:1']/opendaylight-inventory:node-connector[opendaylight-inventory:id='openflow:1:1']",
          u'tp-id': u'openflow:1:1'
        },
        {
          u'opendaylight-topology-inventory:inventory-node-connector-ref': u"/opendaylight-inventory:nodes/opendaylight-inventory:node[opendaylight-inventory:id='openflow:1']/opendaylight-inventory:node-connector[opendaylight-inventory:id='openflow:1:LOCAL']",
          u'tp-id': u'openflow:1:LOCAL'
        }
      ]
    },
    {
      u'host-tracker-service:addresses': [
        {
          u'first-seen': 1562655393902,
          u'ip': u'10.0.0.1',
          u'mac': u'00:00:00:00:00:01',
          u'id': 6,
          u'last-seen': 1562655393902
        }
      ],
      u'host-tracker-service:id': u'00:00:00:00:00:01',
      u'host-tracker-service:attachment-points': [
        {
          u'active': True,
          u'corresponding-tp': u'host:00:00:00:00:00:01',
          u'tp-id': u'openflow:1:1'
        }
      ],
      u'node-id': u'host:00:00:00:00:00:01',
      u'termination-point': [
        {
          u'tp-id': u'host:00:00:00:00:00:01'
        }
      ]
    },
    {
      u'opendaylight-topology-inventory:inventory-node-ref': u"/opendaylight-inventory:nodes/opendaylight-inventory:node[opendaylight-inventory:id='openflow:2']",
      u'node-id': u'openflow:2',
      u'termination-point': [
        {
          u'opendaylight-topology-inventory:inventory-node-connector-ref': u"/opendaylight-inventory:nodes/opendaylight-inventory:node[opendaylight-inventory:id='openflow:2']/opendaylight-inventory:node-connector[opendaylight-inventory:id='openflow:2:LOCAL']",
          u'tp-id': u'openflow:2:LOCAL'
        },
        {
          u'opendaylight-topology-inventory:inventory-node-connector-ref': u"/opendaylight-inventory:nodes/opendaylight-inventory:node[opendaylight-inventory:id='openflow:2']/opendaylight-inventory:node-connector[opendaylight-inventory:id='openflow:2:1']",
          u'tp-id': u'openflow:2:1'
        },
        {
          u'opendaylight-topology-inventory:inventory-node-connector-ref': u"/opendaylight-inventory:nodes/opendaylight-inventory:node[opendaylight-inventory:id='openflow:2']/opendaylight-inventory:node-connector[opendaylight-inventory:id='openflow:2:2']",
          u'tp-id': u'openflow:2:2'
        }
      ]
    },
    {
      u'host-tracker-service:addresses': [
        {
          u'first-seen': 1562655393906,
          u'ip': u'10.0.0.2',
          u'mac': u'00:00:00:00:00:02',
          u'id': 7,
          u'last-seen': 1562655393906
        }
      ],
      u'host-tracker-service:id': u'00:00:00:00:00:02',
      u'host-tracker-service:attachment-points': [
        {
          u'active': True,
          u'corresponding-tp': u'host:00:00:00:00:00:02',
          u'tp-id': u'openflow:2:1'
        }
      ],
      u'node-id': u'host:00:00:00:00:00:02',
      u'termination-point': [
        {
          u'tp-id': u'host:00:00:00:00:00:02'
        }
      ]
    }
  ],
  u'link': [
    {
      u'link-id': u'host:00:00:00:00:00:01/openflow:1:1',
      u'destination': {
        u'dest-node': u'openflow:1',
        u'dest-tp': u'openflow:1:1'
      },
      u'source': {
        u'source-tp': u'host:00:00:00:00:00:01',
        u'source-node': u'host:00:00:00:00:00:01'
      }
    },
    {
      u'link-id': u'openflow:2:1/host:00:00:00:00:00:02',
      u'destination': {
        u'dest-node': u'host:00:00:00:00:00:02',
        u'dest-tp': u'host:00:00:00:00:00:02'
      },
      u'source': {
        u'source-tp': u'openflow:2:1',
        u'source-node': u'openflow:2'
      }
    },
    {
      u'link-id': u'openflow:1:2',
      u'destination': {
        u'dest-node': u'openflow:2',
        u'dest-tp': u'openflow:2:2'
      },
      u'source': {
        u'source-tp': u'openflow:1:2',
        u'source-node': u'openflow:1'
      }
    },
    {
      u'link-id': u'openflow:2:2',
      u'destination': {
        u'dest-node': u'openflow:1',
        u'dest-tp': u'openflow:1:2'
      },
      u'source': {
        u'source-tp': u'openflow:2:2',
        u'source-node': u'openflow:2'
      }
    },
    {
      u'link-id': u'openflow:1:1/host:00:00:00:00:00:01',
      u'destination': {
        u'dest-node': u'host:00:00:00:00:00:01',
        u'dest-tp': u'host:00:00:00:00:00:01'
      },
      u'source': {
        u'source-tp': u'openflow:1:1',
        u'source-node': u'openflow:1'
      }
    },
    {
      u'link-id': u'host:00:00:00:00:00:02/openflow:2:1',
      u'destination': {
        u'dest-node': u'openflow:2',
        u'dest-tp': u'openflow:2:1'
      },
      u'source': {
        u'source-tp': u'host:00:00:00:00:00:02',
        u'source-node': u'host:00:00:00:00:00:02'
      }
    }
  ],
  u'topology-id': u'flow:1'
}

仍在尝试解决它...到目前为止没有运气...

需要从 API 调用中获取所有节点和链接(源和目标)并将其保存到 json 文件并发送到 d3.js 进行图形可视化。请指教。谢谢

【问题讨论】:

    标签: python rest api d3.js networkx


    【解决方案1】:

    这个for循环:

    for link in range(len(topology['link'])):
        e = (link['link']['destination']['node']['node-id'], link['link']['source']['node']['node-id'])
        graph.add_edge(*e)
    

    告诉 Python 将 012 的值分配给 link,直到 topology['link'] 的长度(嗯,长度减 1)。这解释了当 for 循环第一次尝试在整数 0 中查找条目 ['link'] 时出现的错误。整数没有这样的条目。

    你的意思是做for link in topology['link']: 还是别的什么?看来您希望 link 是某种形式的字典。


    您的代码还有其他问题。

    for i in range(len(topology['link'])):
        print "Link ID - ", topology['link'][i]['link-id']
        i += 1
    

    i+=1 在块的末尾没有多大意义,因为下一次循环时,i 会从 for 循环中获得一个新值。我还想知道在topology['node'] 上的 for 循环中是否存在隐藏错误,类似于循环中给出错误的错误。

    【讨论】:

    • 嗨乔尔...我已经从程序中排除链接并保留与节点相关的代码,它确实可以将节点列表发送到 topo.json 并能够通过 d3 查看节点(当然没有链接)......我在for循环链接的某个地方没有问题......但现在我卡在这里......我获得节点和链接的来源来自我通过rest api调用的拓扑细节。 ..我在上面的帖子中分享了详细信息...感谢您的回复
    • ``` for i in range(len(topology['link'])): print "Link ID - ", topology['link'][i]['link-id'] i += 1 ``` 这给出了如下链接列表 ``` 链接列表:链接 ID - 主机:00:00:00:00:00:01/openflow:1:1 链接 ID - openflow:2:1 /host:00:00:00:00:00:02 链接 ID - openflow:1:2 链接 ID - openflow:2:2 链接 ID - openflow:1:1/host:00:00:00:00:00 :01 Link ID - host:00:00:00:00:00:02/openflow:2:1 ```我认为问题是当我想在networkx图上添加链接时......
    猜你喜欢
    • 2016-01-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多