使用NetworkX和Matplotlib炫彩呈现网络增长

17

我想为一个随着时间增长而逐渐变大的图表添加动画效果。

目前我的进展如下:

fig = plt.figure()
ims = []
graph = nx.Graph()
for i in range(50):
    // Code to modify Graph
    nx.draw(graph, pos=nx.get_node_attributes(graph,'Position'))
    im = plt.draw()
    self.ims.append([im])
ani = animation.ArtistAnimation(fig, ims, interval=50, blit=True,repeat_delay=1000)
ani.save('dynamic_images.mp4')
plt.show()

然而,我收到了以下错误信息:

 File "main.py", line 204, in <module>
    repeat_delay=1000)
  File "/usr/lib/pymodules/python2.7/matplotlib/animation.py", line 356, in __init__
    TimedAnimation.__init__(self, fig, *args, **kwargs)
  File "/usr/lib/pymodules/python2.7/matplotlib/animation.py", line 304, in __init__
    Animation.__init__(self, fig, event_source=event_source, *args, **kwargs)
  File "/usr/lib/pymodules/python2.7/matplotlib/animation.py", line 53, in __init__
    self._init_draw()
  File "/usr/lib/pymodules/python2.7/matplotlib/animation.py", line 363, in _init_draw
    artist.set_visible(False)
AttributeError: 'NoneType' object has no attribute 'set_visible'
nicomoto@nicomoto-VirtualBox:~/Desktop/CS8903-SpecialProblem/Code/
我想要的是一种动画,可以看到图表的增长过程。我可以在每个阶段保存图表,并可能能够在matplotlib之外创建动画,但有没有办法让它像这样工作呢?

你的后端是什么?我在一些后端遇到了一些动画问题。你能运行matplotlib的basic_example.py吗? - tiago
是的,这对我来说完美无缺。至于后端,我只是在Ubuntu上使用Python 2.7、NumPy、SciPy、NetworkX和Matplotlib……所有这些都是最近几天安装的,所以它们都是最新版本的……我基本上是一名学生,正在尝试一些实验,如果能将这些图形动画化,那将非常有帮助,这样我就可以看到它们是如何增长的! - Nicomoto
我对networkx不太熟悉。也许问题在于ArtistAnimation期望的是一个matplotlib的图形对象,而不是nx对象? - tiago
更新了我的回答,希望更有帮助。 - brentlance
3个回答

17

一个改进版本的bretlance。希望它会有所帮助。它将显示动画,而不是一张又一张的图片

仍然不知道问题的所有者如何利用matplotlib的动画, Animate drawing networkx edges

#!/usr/bin/env python
import random
import pylab
from matplotlib.pyplot import pause
import networkx as nx
pylab.ion()

graph = nx.Graph()
node_number = 0
graph.add_node(node_number, Position=(random.randrange(0, 100), random.randrange(0, 100)))

def get_fig():
    global node_number
    node_number += 1
    graph.add_node(node_number, Position=(random.randrange(0, 100), random.randrange(0, 100)))
    graph.add_edge(node_number, random.choice(graph.nodes()))
    nx.draw(graph, pos=nx.get_node_attributes(graph,'Position'))

num_plots = 50;
pylab.show()

for i in range(num_plots):

    get_fig()
    pylab.draw()
    pause(2)

正是我在寻找的。从一个图形到另一个图形之间的过渡很好。减少暂停时间可以得到平滑的动画效果。谢谢。 :) - mythicalcoder

10

经过审查,我认为那段代码与这个问题不太相关。但是,我能够利用此SO答案此SO答案来为您组合出一个答案。以下是将创建一个图形、添加50个随机节点和50个随机边缘,并在添加每个节点和边缘后显示图形的代码。与您的代码相比,有一些关键的改变:

  1. 此代码基于使用pylab.ion()(详见此处)。
  2. 您的代码尝试使用一个图形并更改其中的图像。此代码为每个帧创建一个新图形。
  3. 此代码不写出为.mp4文件。如果确实需要,我建议在渲染时将图形写入.png文件,然后事后再转换为mp4。
  4. 请注意,此代码使用matplotlib.pyplot.pause()而非time.sleep()。如果使用time.sleep(),则图形将无法呈现。

祝好运!

import random
import pylab
from matplotlib.pyplot import pause
import networkx as nx
pylab.ion()

graph = nx.Graph()
node_number = 0
graph.add_node(node_number, Position=(random.randrange(0, 100), random.randrange(0, 100)))

def get_fig():
    global node_number
    node_number += 1
    graph.add_node(node_number, Position=(random.randrange(0, 100), random.randrange(0, 100)))
    graph.add_edge(node_number, random.choice(graph.nodes()))
    fig = pylab.figure()
    nx.draw(graph, pos=nx.get_node_attributes(graph,'Position'))
    return fig

num_plots = 50;
pylab.show()

for i in range(num_plots):

    fig = get_fig()
    fig.canvas.draw()
    pylab.draw()
    pause(2)
    pylab.close(fig)

抱歉耽搁了,不管怎样你的建议让我开始思考。首先我画了图表并存储为单独的PNG文件,然后在外部将它们拼接在一起...我还使用离子进行了实现,唯一的问题是我无法将其保存为gif文件,但你可以看到运行时的变化效果相当酷炫。 - Nicomoto
谢谢!我的意思是想尝试使用matplotlib.animation.FuncAnimation的另一种解决方案(请参阅http://matplotlib.org/api/animation_api.html了解更多信息),但我还没有时间。 - brentlance
@Skyler 这段代码相当老了,而且库已经更新。一个简单的解决方法是使用random.choice(list(graph.nodes()))代替random.choice(graph.nodes())。我刚刚添加了一个新答案,展示了现在代码可能会是什么样子。 - JohanC

6
由于现有的答案相当陈旧,这里提供了使用当前版本的matplotlib和networkx的代码示例。
import random
import networkx as nx
import matplotlib.pyplot as plt

graph = nx.Graph()
num_plots = 50
for node_number in range(num_plots):
    graph.add_node(node_number, Position=(random.randrange(0, 100), random.randrange(0, 100)))
    graph.add_edge(node_number, random.choice(list(graph.nodes())))
    nx.draw(graph, pos=nx.get_node_attributes(graph,'Position'))
    plt.pause(0.5)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接