Sunday, September 24, 2006

Dynamic Plot on Python

之前介紹 Python 在複雜網路模擬實驗的應用時,曾提到用 matplotlib 來繪製該實驗的圖表。其模仿 Matlab 的繪圖功能,用起來方便,所繪製的圖也在水準之上。有圖有真相,這就秀秀用 matplotlib 為該實驗繪製的兩張圖表:

學長看了後提議:某些實驗邊跑模擬的同時,也把產生的數據動態繪出,效果會更好。

憑著殘留印象,我把相關用法的說明再次翻出來研讀,寫了下列的 Python code 來測試:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
"""
Interactive random dot plotting.
 
This module demonstrates the usage of the interactive mode of matplotlib.
It is suggested to run this code under ipython. Details please see
http://matplotlib.sourceforge.net/interactive.html
 
 
Usage
=====
 
You can run this module in three ways:
 
    1. As a stand-alone application with GUI
    2. Run it on command line with a -d parameter to just generate the
       image with a specific format. (without GUI)
        * ref. http://matplotlib.sourceforge.net/backends.html
    3. Run it on ipython to call loop() many times
 
Examples
--------
You can simply run this module as a stand-alone application with GUI
 
    > irandot.py
 
Or just generate a image file with a specific format:
 
    > irandot.py -dAGG     # generate PNG file
    > irandot.py -dPS      # generate PS file
    > irandot.py -dSVG     # generate SVG file
    > irandot.py -dEMF     # generate EMF file
 
Running it with ipython is strongly suggested.
 
    In [1]: cd I:\trial\python  # suppose the module is put in I:\trial\python
    ...
    In [2]: run irandot.py
    ...
    In [3]: loop(50)
    ...
    In [4]: loop(20)
    ...
 
"""
__author__ = "Jiang Yu-Kuan, yukuan.jiang(at)gmail.com"
__date__ = "2006/09/24~2006/9/25"
__revision__ = "1.3"
 
from pylab import *
 
 
def dot_gen(dots=2):
    """A random dot generator.
 
    - dots: number of dots with plotting each loop
    """
    i = 0
    while 1:
        l, = plot(rand(dots), rand(dots), 'go')
        #setp(l, alpha=1,
        #    markerfacecolor='w', markeredgecolor='g', markersize=10)
        i += dots
        yield i
 
 
def loop(n=1):
    """Repeat dot plotting of n times."""
    g= dot_gen()  # gets a dot-plotting generator
    for i in xrange(n):
        print g.next(),
 
 
if __name__ == '__main__':
    if not isinteractive():
        ion()  # turns interactive on
 
    loop(50)
    savefig('irandot')
 
    try:
        __IPYTHON__
    except NameError:
        print "\nNOT on IPython"
        show()
    else:
        print "\nOn IPython"
  • 行 59 是真正畫綠點的指令。
  • 行 75 是關鍵所在,它切換 matplotlib 到互動模式。
  • 行 80~86 是為了在 IPython 下不要執行 show()

這個程式取名為 irandot.py ,可以當作一般的執行檔,點兩下檔名執行。執行時我們可以看到隨機產生的座標,一點一點地在座標圖上冒出。以下是其 screenshot:

此外,強烈建議在 IPython shell 下執行 irandot.py:

  1. 開啟 IPython shell
  2. 在 IPython shell 敲進 "cd I:/trial/python" 來切換到存放 irandot.py 的目錄。
  3. 鍵入 "run irandot" 後就會繪出類似上面那幅 2*50=100 個綠點的隨機圖。
  4. 再鍵入 "loop(100)" ,程式會陸續再冒出 2*100 = 200 個綠點。
  5. 高興的話,可以一直下 loop 、改變參數,讓綠點繼續冒下去。

後記:

  • 之前發現無論在 IDLEPythonWin 下,圖表反覆繪製幾次,程式就會掛點的問題。碰巧藉這次測試,找到解法了。作法很簡單,只要改用 IPython shell 即可。
  • 如果你也是裝 Python Enthought 來用,那 IPython 已經在你電腦了。
  • 目前的經驗,開發過程使用 IDLEPythonWin 順手,測試寫好的程式則用 IPython 較方便
  • 如果嫌上述開發環境太陽春,我推薦 SPE
  • Python Enthought 附的 matplotlib 有些小 bug 。可以到這裡下載新版 matplotlib 安裝程式來更新。其底層還用到 NumPy ,可到這裡下載安裝。

10 comments:

York said...

剛剛在 Matplotlib 網站上逛到 這個 FAQ ,其中提到了 anim.pysystem_monitor.py 這兩個程式,為 Dynamic Plot 作了很好的示範效果。

York said...

原來 Matplotlib 跟許多 IDE 水土不服的問題,其 FAQ ,例如這則這則,也有提到。

York said...

今天成功讓 matplotlib 存 EMF 格式的檔案了!

EMF 是 Office 通行的向量圖格式。透過 Microsoft Office Picture Manager 可以很容易開檔,然後剪貼到例如 PowrPoint 投影片上,接下來就可以進一步把向量圖解開群組,並就各個子圖作修改。

詳細的用法可以參考 matplotlib backends 裡的說明。

York said...

今天在 SciPy.org 發現一則 Matplotlib Animation 的 Cookbook ,對這個主題,作了詳盡的介紹。

Anonymous said...

如果覺得IPython真的用的不習慣的話,
可以把matplotlib的backend換掉,
他有一個叫做matplotlibrc的檔案,
在安裝的資料夾搜尋依下,如果是在windows下的話,將它複製到C:\Documents and Settings\使用者名稱\.matplotlib\ 下
然後內容中有個 backend 我是將它改成WXAgg 然後就沒有出現什麼問題, 他有很多個backend可以挑, 一個個試試看。

#### CONFIGURATION BEGINS HERE
# the default backend; one of GTK GTKAgg GTKCairo FltkAgg QtAgg TkAgg
# Agg Cairo GD GDK Paint PS PDF SVG Template
backend : WXAgg

Drake said...

我現在有個數學函式,想用它來看一下長的樣子,公式可能如下:


f(x) = {
x , if x < 50
sin(x) , if x >= 50 and x < 100
x*x+2*x+3 , if x >= 100

類似這種函式的話,要怎麼利用 matplotlib 來很快地得到一個 plot 呢? 我一開始只有想到使用 list comprehensions,先弄個三個 list,然後 join 起來,再餵給 plot(),不過感覺有點麻煩呢~ 如果可以直接把函數與值域餵給 plot,然後它就幫忙畫出來,那就太棒了 :p

我也可能是在問一個很簡單的問題 XD

Drake said...

忘了 email follow-up :p

York said...

To Drake,

你何不按照自己的想法,先試寫看看?
無論如何,也沒幾行,是我的版本,請參考。

Drake said...

我想我真的問了一個笨問題
感謝提醒 :)

Hua said...

今天用IPython跑anim.py, 結果情況跟在IDLE跑時一樣, run個幾秒就停住了. 可能是我的環境沒辦法讓IPython發揮所長吧QQ