ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

python – 动画网络图以显示算法的进度

2019-07-03 02:46:02  阅读:286  来源: 互联网

标签:python algorithm animation matplotlib networkx


我想为网络图设置动画以显示算法的进度.我正在使用NetworkX进行图表创建.

this SO answer开始,我想出了一个解决方案,使用来自IPython.display的clear_ouput和命令plt.pause()来管理动画的速度.这适用于具有少量节点的小图,但是当我在10×10网格上实现时,动画非常慢并且减少了plt.pause()中的参数似乎对动画速度没有任何影响.这是一个实现Dijkstra算法的MME,我在算法的每次迭代中更新节点的颜色:

import math
import queue
import random
import networkx as nx
import matplotlib.pyplot as plt
from IPython.display import clear_output
%matplotlib inline

# plotting function
def get_fig(G,current,pred): 
    nColorList = []
    for i in G.nodes():        
        if i == current: nColorList.append('red')
        elif i==pred: nColorList.append('white')
        elif i==N: nColorList.append('grey')        
        elif node_visited[i]==1:nColorList.append('dodgerblue')
        else: nColorList.append('powderblue')
    plt.figure(figsize=(10,10))
    nx.draw_networkx(G,pos,node_color=nColorList,width=2,node_size=400,font_size=10)
    plt.axis('off')
    plt.show()

# graph creation
G=nx.DiGraph()
pos={}
cost={}
for i in range(100):
    x= i % 10
    y= math.floor(i/10)
    pos[i]=(x,y)    
    if i % 10 != 9 and i+1 < 100: 
       cost[(i,i+1)] = random.randint(0,9)
       cost[(i+1,i)] = random.randint(0,9)
    if i+10 < 100: 
       cost[(i,i+10)] = random.randint(0,9)
       cost[(i+10,i)] = random.randint(0,9)
G.add_edges_from(cost)   

# algorithm initialization
lab={}
path={}
node_visited={}
N = random.randint(0,99)
SE = queue.PriorityQueue()
SE.put((0,N))
for i in G.nodes():       
    if i == N: lab[i] = 0        
    else: lab[i] = 9999
    path[i] = None
    node_visited[i] = 0 

# algorithm main loop    
while not SE.empty():
    (l,j) = SE.get()    
    if node_visited[j]==1: continue
    node_visited[j] = 1
    for i in G.predecessors(j):        
        insert_in_SE = 0               
        if lab[i] > cost[(i,j)] + lab[j]:
            lab[i] = cost[(i,j)] + lab[j]
            path[i] = j
            SE.put((lab[i],i))
        clear_output(wait=True)         
        get_fig(G,j,i)
        plt.pause(0.0001)
print('end')

理想情况下,我想在不超过5秒的时间内显示整个动画,而目前需要几分钟才能完成算法,这表明plt.pause(0.0001)无法按预期工作.

在图形动画(post 2post 3)上阅读SO帖子后,似乎可以使用matplotlib中的动画模块来解决这个问题,但我无法在算法中成功实现答案.第2篇中的答案建议使用matplotlib中的FuncAnimation,但我正在努力使更新方法适应我的问题,第3篇中的答案导致了一个很好的教程,提出了类似的建议.

我的问题是如何为我的问题提高动画的速度:是否可以安排clear_output和plt.pause()命令以获得更快的动画,或者我应该使用matplotlib的FuncAnimation?如果是后者,那么我应该如何定义更新功能?

谢谢您的帮助.

编辑1

import math
import queue
import random
import networkx as nx
import matplotlib.pyplot as plt

# plotting function
def get_fig(G,current,pred):   
    for i in G.nodes():        
        if i==current: G.node[i]['draw'].set_color('red')            
        elif i==pred: G.node[i]['draw'].set_color('white')
        elif i==N: G.node[i]['draw'].set_color('grey')        
        elif node_visited[i]==1: G.node[i]['draw'].set_color('dodgerblue')
        else: G.node[i]['draw'].set_color('powderblue')    

# graph creation
G=nx.DiGraph()
pos={}
cost={}
for i in range(100):
    x= i % 10
    y= math.floor(i/10)
    pos[i]=(x,y)    
    if i % 10 != 9 and i+1 < 100: 
        cost[(i,i+1)] = random.randint(0,9)
        cost[(i+1,i)] = random.randint(0,9)
    if i+10 < 100: 
        cost[(i,i+10)] = random.randint(0,9)
        cost[(i+10,i)] = random.randint(0,9)
G.add_edges_from(cost)

# algorithm initialization
plt.figure(1, figsize=(10,10))
lab={}
path={}
node_visited={}
N = random.randint(0,99)
SE = queue.PriorityQueue()
SE.put((0,N))
for i in G.nodes():       
    if i == N: lab[i] = 0        
    else: lab[i] = 9999
    path[i] = None
    node_visited[i] = 0 
    G.node[i]['draw'] = nx.draw_networkx_nodes(G,pos,nodelist=[i],node_size=400,alpha=1,with_labels=True,node_color='powderblue')
for i,j in G.edges():
    G[i][j]['draw']=nx.draw_networkx_edges(G,pos,edgelist=[(i,j)],width=2)    

plt.ion()
plt.draw()
plt.show()

# algorithm main loop  
while not SE.empty():
    (l,j) = SE.get()    
    if node_visited[j]==1: continue
    node_visited[j] = 1
    for i in G.predecessors(j):        
        insert_in_SE = 0               
        if lab[i] > cost[(i,j)] + lab[j]:
            lab[i] = cost[(i,j)] + lab[j]
            path[i] = j
            SE.put((lab[i],i))       
        get_fig(G,j,i)        
        plt.draw()
        plt.pause(0.00001)
plt.close()

编辑2

import math
import queue
import random
import networkx as nx
import matplotlib.pyplot as plt

# graph creation
G=nx.DiGraph()
pos={}
cost={}
for i in range(100):
    x= i % 10
    y= math.floor(i/10)
    pos[i]=(x,y)    
    if i % 10 != 9 and i+1 < 100: 
        cost[(i,i+1)] = random.randint(0,9)
        cost[(i+1,i)] = random.randint(0,9)
    if i+10 < 100: 
        cost[(i,i+10)] = random.randint(0,9)
        cost[(i+10,i)] = random.randint(0,9)
G.add_edges_from(cost)

# algorithm initialization
lab={}
path={}
node_visited={}
N = random.randint(0,99)
SE = queue.PriorityQueue()
SE.put((0,N))
cf = plt.figure(1, figsize=(10,10))    
ax = cf.add_axes((0,0,1,1))
for i in G.nodes():       
    if i == N: 
        lab[i] = 0
        G.node[i]['draw'] = nx.draw_networkx_nodes(G,pos,nodelist=[i],node_size=400,alpha=1.0,node_color='grey')
    else: 
        lab[i] = 9999
        G.node[i]['draw'] = nx.draw_networkx_nodes(G,pos,nodelist=[i],node_size=400,alpha=0.2,node_color='dodgerblue')
    path[i] = None
    node_visited[i] = 0
for i,j in G.edges():
    G[i][j]['draw']=nx.draw_networkx_edges(G,pos,edgelist=[(i,j)],width=3,alpha=0.2,arrows=False)

plt.ion()
plt.show()
ax = plt.gca()
canvas = ax.figure.canvas
background = canvas.copy_from_bbox(ax.bbox)

# algorithm main loop  
while not SE.empty():
    (l,j) = SE.get()    
    if node_visited[j]==1: continue
    node_visited[j] = 1
    if j!=N:
        G.node[j]['draw'].set_color('r')        
    for i in G.predecessors(j):        
        insert_in_SE = 0               
        if lab[i] > cost[(i,j)] + lab[j]:
            lab[i] = cost[(i,j)] + lab[j]
            path[i] = j
            SE.put((lab[i],i))
        if i!=N:            
            G.node[i]['draw'].set_alpha(0.7)
            G[i][j]['draw'].set_alpha(1.0)
        ax.draw_artist(G[i][j]['draw'])
        ax.draw_artist(G.node[i]['draw'])
        ax.draw_artist(G.node[j]['draw'])
        canvas.blit(ax.bbox)    
        plt.pause(0.0001)
plt.close()

解决方法:

如果您的图形不是太大,您可以尝试以下方法来设置单个节点和边的属性.诀窍是保存绘图函数的输出,使您可以处理对象属性,如颜色,透明度和可见性.

import networkx as nx
import matplotlib.pyplot as plt

G = nx.cycle_graph(12)
pos = nx.spring_layout(G)

cf = plt.figure(1, figsize=(8,8))
ax = cf.add_axes((0,0,1,1))

for n in G:
    G.node[n]['draw'] = nx.draw_networkx_nodes(G,pos,nodelist=[n], with_labels=False,node_size=200,alpha=0.5,node_color='r')
for u,v in G.edges():
    G[u][v]['draw']=nx.draw_networkx_edges(G,pos,edgelist=[(u,v)],alpha=0.5,arrows=False,width=5)

plt.ion()
plt.draw()

sp = nx.shortest_path(G,0,6)
edges = zip(sp[:-1],sp[1:])

for u,v in edges:
    plt.pause(1)
    G.node[u]['draw'].set_color('r')
    G.node[v]['draw'].set_color('r')
    G[u][v]['draw'].set_alpha(1.0)
    G[u][v]['draw'].set_color('r')
    plt.draw()

编辑

以下是使用graphviz进行布局的10×10网格示例.
整个过程在我的机器上运行大约1秒钟.

import networkx as nx
import matplotlib.pyplot as plt

G = nx.grid_2d_graph(10,10)
pos = nx.graphviz_layout(G)

cf = plt.figure(1, figsize=(8,8))
ax = cf.add_axes((0,0,1,1))

for n in G:
    G.node[n]['draw'] = nx.draw_networkx_nodes(G,pos,nodelist=[n], with_labels=False,node_size=200,alpha=0.5,node_color='k')
for u,v in G.edges():
    G[u][v]['draw']=nx.draw_networkx_edges(G,pos,edgelist=[(u,v)],alpha=0.5,arrows=False,width=5)

plt.ion()
plt.draw()
plt.show()
sp = nx.shortest_path(G,(0,0),(9,9))
edges = zip(sp[:-1],sp[1:])

for u,v in edges:
    G.node[u]['draw'].set_color('r')
    G.node[v]['draw'].set_color('r')
    G[u][v]['draw'].set_alpha(1.0)
    G[u][v]['draw'].set_color('r')
    plt.draw()

编辑2

这是另一种更快的方法(不重绘轴或所有节点)并使用广度优先搜索算法.这个在我的机器上运行大约2秒钟.我注意到一些后端更快 – 我正在使用GTKAgg.

import networkx as nx
import matplotlib.pyplot as plt

def single_source_shortest_path(G,source):
    ax = plt.gca()
    canvas = ax.figure.canvas
    background = canvas.copy_from_bbox(ax.bbox)
    level=0                  # the current level
    nextlevel={source:1}       # list of nodes to check at next level
    paths={source:[source]}  # paths dictionary  (paths to key from source)
    G.node[source]['draw'].set_color('r')
    G.node[source]['draw'].set_alpha('1.0')
    while nextlevel:
        thislevel=nextlevel
        nextlevel={}
        for v in thislevel:
#            canvas.restore_region(background)
            s = G.node[v]['draw']
            s.set_color('r')
            s.set_alpha('1.0')
            for w in G[v]:
                if w not in paths:
                    n = G.node[w]['draw']
                    n.set_color('r')
                    n.set_alpha('1.0')
                    e = G[v][w]['draw']
                    e.set_alpha(1.0)
                    e.set_color('k')
                    ax.draw_artist(e)
                    ax.draw_artist(n)
                    ax.draw_artist(s)
                    paths[w]=paths[v]+[w]
                    nextlevel[w]=1
                    canvas.blit(ax.bbox)
        level=level+1
    return paths



if __name__=='__main__':

    G = nx.grid_2d_graph(10,10)
    pos = nx.graphviz_layout(G)
    cf = plt.figure(1, figsize=(8,8))
    ax = cf.add_axes((0,0,1,1))

    for n in G:
        G.node[n]['draw'] = nx.draw_networkx_nodes(G,pos,nodelist=[n], with_labels=False,node_size=200,alpha=0.2,node_color='k')
    for u,v in G.edges():
        G[u][v]['draw']=nx.draw_networkx_edges(G,pos,edgelist=[(u,v)],alpha=0.5,arrows=False,width=5)
    plt.ion()
    plt.show()

    path = single_source_shortest_path(G,source=(0,0))

标签:python,algorithm,animation,matplotlib,networkx
来源: https://codeday.me/bug/20190703/1362161.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有