標籤:
matplotlib是基於Python語言的開源項目,旨在為Python提供一個資料繪圖包。Matplotlib 可能是 Python 2D-繪圖領域使用最廣泛的套件。它能讓使用者很輕鬆地將資料圖形化,並且提供多樣化的輸出格式。
matplotlib使用numpy進行數組運算,並調用一系列其他的Python庫來實現硬體互動。matplotlib的核心是一套由對象構成的繪圖API。
你需要安裝Python, numpy和matplotlib。(可以到python.org下載Python編譯器。相關Python包的安裝,請參看我的Python小技巧)
matplotlib的官網是: http://matplotlib.org/ 官網有豐富的圖例和文檔說明。
matplotlib在github的地址為:https://github.com/matplotlib 歡迎有興趣的開發人員fork。
matplotlib是受MATLAB的啟發構建的,模仿MATLAB但是不模仿“收費”
1 一個簡單的例子
(1) 繪圖,畫一條直線
import matplotlib.pyplot as pltplt.plot([0, 1], [0, 1]) # plot a line from (0, 0) to (1, 1)plt.title("a strait line")plt.xlabel("x value")plt.ylabel("y value")plt.savefig("demo.jpg")plt.show()
(2) 解析
上面的代碼實際上封裝了很多,如果我們想簡單的快速繪圖,那麼你只要簡單的調用上面的代碼。但是作為程式員,怎麼能甘心做個調用者,讓我們解開matplotlib的核心面紗吧
第一行,plt.plot([0,1],[0,1])源碼
# 源碼1
def plot(*args, **kwargs): ax = gca() #(1) 獲得axes # allow callers to override the hold state by passing hold=True|False washold = ax.ishold() hold = kwargs.pop(‘hold‘, None) if hold is not None: ax.hold(hold) try: ret = ax.plot(*args, **kwargs) #(2) 調用ax.plot() draw_if_interactive() finally: ax.hold(washold) return ret
我們看到裡面代碼(1) 處調用了gca,當獲得了axes之後,plot是通過ax進行的,代碼(2)
好的,那麼繼續深入ax=gca(),查看gca()的源碼
# 源碼2
def gca(**kwargs): """ Get the current :class:`~matplotlib.axes.Axes` instance on the current figure matching the given keyword args, or create one. If the current axes doesn‘t exist, or isn‘t a polar one, the appropriate axes will be created and then returned. """ ax = gcf().gca(**kwargs) return ax
好吧,實際上裡面還有洞天,繼續追蹤gcf()的源碼
#源碼 3
def gcf(): "Get a reference to the current figure." figManager = _pylab_helpers.Gcf.get_active() #(1) 從figure的active 列表中取出最後面的一個,如果列表為空白,則返回None if figManager is not None: return figManager.canvas.figure #(2) 直接返回當前active figure列表中最上面的那個figure else: return figure() #(3) 如果沒有則建立一個
在這裡獲得一個figure,如果程式裡面有多個figure,則返回正啟用的那個(啟用是指如果有多個視窗,則是最上面的那個,這個視窗接觸滑鼠、鍵盤輸入),如果沒有則建立。建立的時候預設就將這個figure設為啟用的figure。
OK,回溯到源碼2。也就是這個gca()是調用figure的gca(),那麼繼續探索之旅。
#源碼4 figure類的gcadef gca(self, **kwargs): """ Get the current axes, creating one if necessary The following kwargs are supported for ensuring the returned axes adheres to the given projection etc., and for axes creation if the active axes does not exist: %(Axes)s """ ckey, cax = self._axstack.current_key_axes() #(1) 粗糙axes的是stack # if there exists an axes on the stack see if it maches # the desired axes configuration if cax is not None: # if no kwargs are given just return the current axes # this is a convenience for gca() on axes such as polar etc. if not kwargs: return cax # if the user has specified particular projection detail # then build up a key which can represent this else: # we don‘t want to modify the original kwargs # so take a copy so that we can do what we like to it kwargs_copy = kwargs.copy() projection_class, _, key = process_projection_requirements( self, **kwargs_copy) # let the returned axes have any gridspec by removing it from # the key ckey = ckey[1:] key = key[1:] # if the cax matches this key then return the axes, otherwise # continue and a new axes will be created if key == ckey and isinstance(cax, projection_class): return cax # no axes found, so create one which spans the figure return self.add_subplot(1, 1, 1, **kwargs)
這裡和上面gcf類似,也是看是否有已經存在的,如果存在axes,則直接調用,如果不存在,則是通過figure.add_subplot(1,1,1)建立一個axes。
好了,到這邊為止,我們通過查看源碼已經深入的接觸了figure,axes。實際簡單的一句plt.plot() 是通過figure上得axes調用plot()實現的。
因此我們可以自己寫
fig1 = plt.figure(‘fig1‘) #獲得一個figure, 這個figure是接下來所有畫在這上面對象的載體。可以理解為邊框fig1_axes_1 = fig1.add_axes([0.1, 0.1, 0.8, 0.8])fig1_axes_1.plot([0,1],[0,1])
2 理清關係
接下來的內容很多轉載自http://www.cnblogs.com/vamei/archive/2013/01/30/2879700.html
我們將上面的直線繪圖更改為物件導向式(OO, object-oriented)的,為此,我們引入兩個類: Figure和FigureCanvas。(函數式編程也調用了這些類,只是調用的過程被函數調用所遮掩。)
# object-oriented plotfrom matplotlib.figure import Figurefrom matplotlib.backends.backend_agg import FigureCanvasAgg as FigureCanvasfig = Figure()canvas = FigureCanvas(fig)ax = fig.add_axes([0.1, 0.1, 0.8, 0.8])line, = ax.plot([0,1], [0,1])ax.set_title("a straight line (OO)")ax.set_xlabel("x value")ax.set_ylabel("y value")canvas.print_figure(‘demo.jpg‘)
上面的例子中,我們至少構建了四個對象: fig, canvas, ax, line。它們分別屬於Figure類,FigureCanvas類,Axes類和Line2D類。(使用obj.__class__.__name__來查詢對象所屬的類)
在深入各個對象之前,我們先來做一個比喻。看下面一個圖片:
可以看到,圖中有一個房子,房子上有窗戶和門,窗戶上有條紋,門上有把手,此外映像外還有一隻小烏龜。我們所提到的房子,窗戶,門,條紋,把手,都可以稱其為對象。不同的對象之間有依附關係,比如窗戶和門屬於房子,而把手屬於門。烏龜和房子則是並行的兩個對象。此外,整個映像外有一個方框,用來表明可繪圖的範圍,所有上面提到的元素都依附於該方框。
這就是用物件導向的方式來理解一個映像。事實上,對象是描述映像的最自然的方式,物件導向編程最成功的領域就是在電腦圖形方面。
我們先來看什麼是Figure和Axes對象。在matplotlib中,整個映像為一個Figure對象。在Figure對象中可以包含一個,或者多個Axes對象。每個Axes對象都是一個擁有自己座標系統的繪圖區域。其邏輯關係如下:
轉過頭來看直線圖。整個映像是fig對象。我們的繪圖中只有一個座標系地區,也就是ax。此外還有以下對象。(括弧中表示對象的基本類型)
Title為標題。Axis為座標軸,Label為座標軸標註。Tick為刻度標記,Tick Label為刻度注釋。各個對象之間有下面的對象隸屬關係:
(yaxis同樣有tick, label和tick label,沒有畫出)
儘管data是資料繪圖的關鍵區段,也就是資料本身的圖形化顯示,但是必須和xaxis, yaxis, title一起,才能真正構成一個繪圖區域axes。一個單純的,無法讀出刻度的線是沒有意義的。xaxis, yaxis, title合起來構成了資料的輔助部分(data guide)。
上面元素又包含有多種圖形元素。比如說,我們的data對象是一條線(Line2D)。title, tick label和label都是文本(Text),而tick是由短線(Line 2D)和tick label構成,xaxis由座標軸的線和tick以及label構成,ax由xaxis, yaxis, title, data構成,ax自身又構成了fig的一部分。上面的每個對象,無論是Line2D, Text還是fig,它們都來自於一個叫做Artist的基類。
OO繪圖的原程式還有一個canvas對象。它代表了真正進行繪圖的後端(backend)。Artist只是在程式邏輯上的繪圖,它必須串連後端繪圖程式才能真正在螢幕上繪製出來(或者儲存為檔案)。我們可以將canvas理解為繪圖的物理(或者說硬體)實現。
在OO繪圖程式中,我們並沒有真正看到title, tick, tick label, xaxis, yaxis對象,而是使用ax.set_*的方法間接設定了這些對象。但這些對象是真實存在的,你可以從上層對象中找到其“真身”。比如,fig.axes[0].xaxis就是我們上面途中的xaxis對象。我們可以通過fig -> axes[0] (也就是ax) -> xaxis的順序找到它。因此,重複我們剛才已經說過的,一個fig就構成了一個完整的映像。對於每個Artist類的對象,都有findobj()方法,來顯示該對象所包含的所有下層對象。
座標
座標是電腦繪圖的基礎。電腦螢幕是由一個個像素點構成的。想要在螢幕上顯示映像,電腦必須告訴螢幕每個像素點上顯示什麼。所以,最貼近硬體的座標體系是以像素為單位的座標體系。我們可以通過具體說明像素位置來標明顯示器上的某一點。這叫做顯示座標(display coordinate),以像素為單位。
然而,像素座標不容易被納入繪圖邏輯。相同的程式,在不同的顯示器上就要調整像素值,以保證映像不變形。所以一般情況下,還會有映像座標和資料座標。
映像座標將一張圖的左下角視為原點,將映像的x方向和y方向總長度都看做1。x方向的0.2就是指20%的映像在x方向的總長,y方向0.8的長度指80%的y方向總長。(0.5, 0.5)是映像的中點,(1, 1)指映像的右上方。比如下面的程式,我們在使用add_axes時,傳遞的參數中,前兩個元素為axes的左下角在fig的映像座標上的位置,後兩個元素指axes在fig的映像座標上x方向和y方向的長度。fig的映像座標稱為Figure座標,儲存在為fig.transFigure
(類似的,每個axes,比如ax1,有屬於自己的映像座標。它以ax1繪圖區域總長作為1,稱為Axes座標。也就是ax1.transAxes。(0.5, 0.5)就表示在Axes的中心。Axes座標和Figure座標原理相似,只是所用的基準地區不同。)
from matplotlib.figure import Figurefrom matplotlib.backends.backend_agg import FigureCanvasAgg as FigureCanvasfig = Figure()canvas = FigureCanvas(fig)# first axesax1 = fig.add_axes([0.1, 0.1, 0.2, 0.2])line, = ax1.plot([0,1], [0,1])ax1.set_title("ax1")# second axesax2 = fig.add_axes([0.4, 0.3, 0.4, 0.5])sca = ax2.scatter([1,3,5],[2,1,2])ax2.set_title("ax2")canvas.print_figure(‘demo.jpg‘)
我們在繪圖,比如使用plot的時候,繪製了兩點間的連線。這兩點分別為(0, 0)和(1, 1)。(plot中的第一個表為兩個x座標,第二個表為兩個y座標)。這時使用的座標係為資料座標系(ax1.transData)。我們可以通過繪出的座標軸讀出資料座標的位置。
如果繪製的是具體資料,那麼資料座標符合我們的需求。如果繪製的是標題這樣的附加資訊,那麼Axes座標符合符合我們的需求。如果是整個映像的註解,那麼Figure座標更符合需求。每一個Artist對象都有一個transform屬性,用於查詢和改變所使用的座標系統。如果為顯示座標,transform屬性為None。
理解matplotlib繪圖