1. 程式人生 > >Python圖表繪製:matplotlib繪相簿入門

Python圖表繪製:matplotlib繪相簿入門

matplotlib 是python最著名的繪相簿,它提供了一整套和matlab相似的命令API,十分適合互動式地行製圖。而且也可以方便地將它作為繪圖控制元件,嵌入GUI應用程式中。

它的文件相當完備,並且Gallery頁面中有上百幅縮圖,開啟之後都有源程式。因此如果你需要繪製某種型別的圖,只需要在這個頁面中瀏覽/複製/貼上一下,基本上都能搞定。

在Linux下比較著名的資料圖工具還有gnuplot,這個是免費的,Python有一個包可以呼叫gnuplot,但是語法比較不習慣,而且畫圖質量不高。

而 Matplotlib則比較強:Matlab的語法、python語言、latex的畫圖質量(還可以使用內嵌的latex引擎繪製的數學公式)。

Matplotlib.pyplot快速繪圖

快速繪圖面向物件方式繪圖

matplotlib實際上是一套面向物件的繪相簿,它所繪製的圖表中的每個繪圖元素,例如線條Line2D、文字Text、刻度等在記憶體中都有一個物件與之對應。

為了方便快速繪圖matplotlib通過pyplot模組提供了一套和MATLAB類似的繪圖API,將眾多繪圖物件所構成的複雜結構隱藏在這套API內部。我們只需要呼叫pyplot模組所提供的函式就可以實現快速繪圖以及設定圖表的各種細節。pyplot模組雖然用法簡單,但不適合在較大的應用程式中使用。

為了將面向物件的繪相簿包裝成只使用函式的呼叫介面,pyplot模組的內部儲存了當前圖表以及當前子圖等資訊。當前的圖表和子圖可以使用plt.gcf()和plt.gca()獲得,分別表示"Get Current Figure"和"Get Current Axes"。在pyplot模組中,許多函式都是對當前的Figure或Axes物件進行處理,比如說:

plt.plot()實際上會通過plt.gca()獲得當前的Axes物件ax,然後再呼叫ax.plot()方法實現真正的繪圖。

可以在Ipython中輸入類似"plt.plot??"的命令檢視pyplot模組的函式是如何對各種繪圖物件進行包裝的。

配置屬性

matplotlib所繪製的圖表的每個組成部分都和一個物件對應,我們可以通過呼叫這些物件的屬性設定方法set_*()或者pyplot模組的屬性設定函式setp()設定它們的屬性值。

因為matplotlib實際上是一套面向物件的繪相簿,因此也可以直接獲取物件的屬性

配置檔案

繪製一幅圖需要對許多物件的屬性進行配置,例如顏色、字型、線型等等。我們在繪圖時,並沒有逐一對這些屬性進行配置,許多都直接採用了matplotlib的預設配置。

matplotlib將這些預設配置儲存在一個名為“matplotlibrc”的配置檔案中,通過修改配置檔案,我們可以修改圖表的預設樣式。配置檔案的讀入可以使用rc_params(),它返回一個配置字典;在matplotlib模組載入時會呼叫rc_params(),並把得到的配置字典儲存到rcParams變數中;matplotlib將使用rcParams字典中的配置進行繪圖;使用者可以直接修改此字典中的配置,所做的改變會反映到此後建立的繪圖元素。

繪製多子圖(快速繪圖)

Matplotlib 裡的常用類的包含關係為 Figure -> Axes -> (Line2D, Text, etc.)一個Figure物件可以包含多個子圖(Axes),在matplotlib中用Axes物件表示一個繪圖區域,可以理解為子圖。

可以使用subplot()快速繪製包含多個子圖的圖表,它的呼叫形式如下:

subplot(numRows, numCols, plotNum)

subplot將整個繪圖區域等分為numRows行* numCols列個子區域,然後按照從左到右,從上到下的順序對每個子區域進行編號,左上的子區域的編號為1。如果numRows,numCols和plotNum這三個數都小於10的話,可以把它們縮寫為一個整數,例如subplot(323)和subplot(3,2,3)是相同的。subplot在plotNum指定的區域中建立一個軸物件。如果新建立的軸和之前建立的軸重疊的話,之前的軸將被刪除。

image

subplot()返回它所建立的Axes物件,我們可以將它用變數儲存起來,然後用sca()交替讓它們成為當前Axes物件,並呼叫plot()在其中繪圖。

繪製多圖表(快速繪圖)

如果需要同時繪製多幅圖表,可以給figure()傳遞一個整數引數指定Figure物件的序號,如果序號所指定的Figure物件已經存在,將不建立新的物件,而只是讓它成為當前的Figure物件。

import numpy as np
import matplotlib.pyplot as plt
plt.figure(1) # 建立圖表1
plt.figure(2) # 建立圖表2
ax1 = plt.subplot(211) # 在圖表2中建立子圖1
ax2 = plt.subplot(212) # 在圖表2中建立子圖2
x = np.linspace(0, 3, 100)
for i in xrange(5):
    plt.figure(1)  #❶ # 選擇圖表1
    plt.plot(x, np.exp(i*x/3))
    plt.sca(ax1)   #❷ # 選擇圖表2的子圖1
    plt.plot(x, np.sin(i*x))
    plt.sca(ax2)  # 選擇圖表2的子圖2
    plt.plot(x, np.cos(i*x))
plt.show()

/tech/static/books/scipy/_images/matplotlib_multi_figure.png

matplotlib的預設配置檔案中所使用的字型無法正確顯示中文。為了讓圖表能正確顯示中文,可以有幾種解決方案。

  1. 在程式中直接指定字型。
  2. 在程式開頭修改配置字典rcParams。
  3. 修改配置檔案。
面向物件畫圖

matplotlib API包含有三層,Artist層處理所有的高層結構,例如處理圖表、文字和曲線等的繪製和佈局。通常我們只和Artist打交道,而不需要關心底層的繪製細節。

直接使用Artists建立圖表的標準流程如下:

  • 建立Figure物件
  • 用Figure物件建立一個或者多個Axes或者Subplot物件
  • 呼叫Axies等物件的方法建立各種簡單型別的Artists
import matplotlib.pyplot as plt
X1 = range(0, 50)
Y1 = [num**2 for num in X1] # y = x^2
X2 = [0, 1]
Y2 = [0, 1]  # y = x
Fig = plt.figure(figsize=(8,4))                      # Create a `figure' instance
Ax = Fig.add_subplot(111)               # Create a `axes' instance in the figure
Ax.plot(X1, Y1, X2, Y2)                 # Create a Line2D instance in the axes
Fig.show()
Fig.savefig("test.pdf")

參考:

什麼是 Matplotlib (主要講面向物件繪圖,對於新手可能有點亂)

Matplotlib.pylab快速繪圖

matplotlib還提供了一個名為pylab的模組,其中包括了許多NumPy和pyplot模組中常用的函式,方便使用者快速進行計算和繪圖,十分適合在IPython互動式環境中使用。這裡使用下面的方式載入pylab模組:
>>> import pylab as pl

1 安裝numpy和matplotlib

>>> import numpy
>>> numpy.__version__

>>> import matplotlib
>>> matplotlib.__version__

2 兩種常用圖型別:Line and scatter plots(使用plot()命令), histogram(使用hist()命令)

2.1 折線圖&散點圖 Line and scatter plots

2.1.1 折線圖 Line plots(關聯一組x和y值的直線)

import numpy as np
import pylab as pl
x = [1, 2, 3, 4, 5]# Make an array of x values
y = [1, 4, 9, 16, 25]# Make an array of y values for each x value
pl.plot(x, y)# use pylab to plot x and y
pl.show()# show the plot on the screen

image

2.1.2 散點圖 Scatter plots

把pl.plot(x, y)改成pl.plot(x, y, 'o')即可,下圖的藍色版本

2.2  美化 Making things look pretty

2.2.1 線條顏色 Changing the line color

紅色:把pl.plot(x, y, 'o')改成pl.plot(x, y, ’or’)

image

image

2.2.2 線條樣式 Changing the line style

虛線:plot(x,y, '--')

image

2.2.3 marker樣式 Changing the marker style

藍色星型markers:plot(x,y, ’b*’)

image

2.2.4 圖和軸標題以及軸座標限度 Plot and axis titles and limits

import numpy as np
import pylab as pl
x = [1, 2, 3, 4, 5]# Make an array of x values
y = [1, 4, 9, 16, 25]# Make an array of y values for each x value
pl.plot(x, y)# use pylab to plot x and y
pl.title(’Plot of y vs. x’)# give plot a title
pl.xlabel(’x axis’)# make axis labels
pl.ylabel(’y axis’)
pl.xlim(0.0, 7.0)# set axis limits
pl.ylim(0.0, 30.)
pl.show()# show the plot on the screen

image

2.2.5 在一個座標系上繪製多個圖 Plotting more than one plot on the same set of axes

做法是很直接的,依次作圖即可:

import numpy as np
import pylab as pl
x1 = [1, 2, 3, 4, 5]# Make x, y arrays for each graph
y1 = [1, 4, 9, 16, 25]
x2 = [1, 2, 4, 6, 8]
y2 = [2, 4, 8, 12, 16]
pl.plot(x1, y1, ’r’)# use pylab to plot x and y
pl.plot(x2, y2, ’g’)
pl.title(’Plot of y vs. x’)# give plot a title
pl.xlabel(’x axis’)# make axis labels
pl.ylabel(’y axis’)
pl.xlim(0.0, 9.0)# set axis limits
pl.ylim(0.0, 30.)
pl.show()# show the plot on the screen

image

2.2.6  圖例 Figure legends

pl.legend((plot1, plot2), (’label1, label2’), 'best’, numpoints=1)

其中第三個引數表示圖例放置的位置:'best’‘upper right’, ‘upper left’, ‘center’, ‘lower left’, ‘lower right’.

如果在當前figure裡plot的時候已經指定了label,如plt.plot(x,z,label="$cos(x^2)$"),直接呼叫plt.legend()就可以了哦。

import numpy as np
import pylab as pl
x1 = [1, 2, 3, 4, 5]# Make x, y arrays for each graph
y1 = [1, 4, 9, 16, 25]
x2 = [1, 2, 4, 6, 8]
y2 = [2, 4, 8, 12, 16]
plot1 = pl.plot(x1, y1, ’r’)# use pylab to plot x and y : Give your plots names
plot2 = pl.plot(x2, y2, ’go’)
pl.title(’Plot of y vs. x’)# give plot a title
pl.xlabel(’x axis’)# make axis labels
pl.ylabel(’y axis’)
pl.xlim(0.0, 9.0)# set axis limits
pl.ylim(0.0, 30.)
pl.legend([plot1, plot2], (’red line’, ’green circles’), ’best’, numpoints=1)# make legend
pl.show()# show the plot on the screen

image

2.3 直方圖 Histograms

import numpy as np
import pylab as pl
# make an array of random numbers with a gaussian distribution with
# mean = 5.0
# rms = 3.0
# number of points = 1000
data = np.random.normal(5.0, 3.0, 1000)
# make a histogram of the data array
pl.hist(data)
# make plot labels
pl.xlabel(’data’)
pl.show()

如果不想要黑色輪廓可以改為pl.hist(data, histtype=’stepfilled’)

image

2.3.1 自定義直方圖bin寬度 Setting the width of the histogram bins manually

增加這兩行

bins = np.arange(-5., 16., 1.) #浮點數版本的range
pl.hist(data, bins, histtype=’stepfilled’)

image

3 同一畫板上繪製多幅子圖 Plotting more than one axis per canvas

如果需要同時繪製多幅圖表的話,可以是給figure傳遞一個整數引數指定圖示的序號,如果所指定
序號的繪圖物件已經存在的話,將不建立新的物件,而只是讓它成為當前繪圖物件。

fig1 = pl.figure(1)
pl.subplot(211)
subplot(211)把繪圖區域等分為2行*1列共兩個區域, 然後在區域1(上區域)中建立一個軸物件. pl.subplot(212)在區域2(下區域)建立一個軸物件。
image

You can play around with plotting a variety of layouts. For example, Fig. 11 is created using the following commands:

f1 = pl.figure(1)
pl.subplot(221)
pl.subplot(222)
pl.subplot(212)

image

當繪圖物件中有多個軸的時候,可以通過工具欄中的Configure Subplots按鈕,互動式地調節軸之間的間距和軸與邊框之間的距離。如果希望在程式中調節的話,可以呼叫subplots_adjust函式,它有left, right, bottom, top, wspace, hspace等幾個關鍵字引數,這些引數的值都是0到1之間的小數,它們是以繪圖區域的寬高為1進行正規化之後的座標或者長度。

pl.subplots_adjust(left=0.08, right=0.95, wspace=0.25, hspace=0.45)

4 繪製檔案中的資料Plotting data contained in files

4.1 從Ascii檔案中讀取資料 Reading data from ascii files

讀取檔案的方法很多,這裡只介紹一種簡單的方法,更多的可以參考官方文件和NumPy快速處理資料(檔案存取)

numpy的loadtxt方法可以直接讀取如下文字資料到numpy二維陣列

**********************************************

# fakedata.txt
0 0
1 1
2 4
3 9
4 16
5 25
6 36
7 49
8 64
9 81
0 0
1 1
2 4
3 9
4 16
5 25
6 36
7 49
8 64
9 81

**********************************************

import numpy as np
import pylab as pl
# Use numpy to load the data contained in the file
# ’fakedata.txt’ into a 2-D array called data
data = np.loadtxt(’fakedata.txt’)
# plot the first column as x, and second column as y
pl.plot(data[:,0], data[:,1], ’ro’)
pl.xlabel(’x’)
pl.ylabel(’y’)
pl.xlim(0.0, 10.)
pl.show()

image

4.2 寫入資料到檔案 Writing data to a text file

寫檔案的方法也很多,這裡只介紹一種可用的寫入文字檔案的方法,更多的可以參考官方文件。

import numpy as np
# Let’s make 2 arrays (x, y) which we will write to a file
# x is an array containing numbers 0 to 10, with intervals of 1
x = np.arange(0.0, 10., 1.)
# y is an array containing the values in x, squared
y = x*x
print ’x = ’, x
print ’y = ’, y
# Now open a file to write the data to
# ’w’ means open for ’writing’
file = open(’testdata.txt’, ’w’)
# loop over each line you want to write to file
for i in range(len(x)):
    # make a string for each line you want to write
    # ’\t’ means ’tab’
    # ’\n’ means ’newline’
    # ’str()’ means you are converting the quantity in brackets to a string type
    txt = str(x[i]) + ’\t’ + str(y[i]) + ’ \n’
    # write the txt to the file
    file.write(txt)
# Close your file
file.close()

對LaTeX數學公式的支援

Matlplotlib對LaTeX有一定的支援,如果記得使用raw字串語法會很自然:

xlabel(r"$\frac{x^2}{y^4}$")

在matplotlib裡面,可以使用LaTex的命令來編輯公式,只需要在字串前面加一個“r”即可

Here is a simple example:

# plain text
plt.title('alpha > beta')

produces “alpha > beta”.

Whereas this:

# math text
plt.title(r'$\alpha > \beta$')

produces "".

這裡給大家看一個簡單的例子。

import matplotlib.pyplot as plt

x = arange(1,1000,1)
r = -2
c = 5
y = [5*(a**r) for a in x]

fig = plt.figure()

ax = fig.add_subplot(111)
ax.loglog(x,y,label = r"$y = \frac{1}{2\sigma_1^2}, c=5,\sigma_1=-2$")
ax.legend()
ax.set_xlabel(r"x")
ax.set_ylabel(r"y")

程式執行結果如圖3所示,這實際上是一個power-law的例子,有興趣的朋友可以繼續google之。

再看一個《用Python做科學計算》中的簡單例子,下面的兩行程式通過呼叫plot函式在當前的繪圖物件中進行繪圖:

plt.plot(x,y,label="$sin(x)$",color="red",linewidth=2)
plt.plot(x,z,"b--",label="$cos(x^2)$")

plot函式的呼叫方式很靈活,第一句將x,y陣列傳遞給plot之後,用關鍵字引數指定各種屬性:

  • label : 給所繪製的曲線一個名字,此名字在圖示(legend)中顯示。只要在字串前後新增"$"符號,matplotlib就會使用其內嵌的latex引擎繪製的數學公式。
  • color : 指定曲線的顏色
  • linewidth : 指定曲線的寬度

詳細的可以參考matplotlib官方教程:

有幾個問題:

  • matplotlib.rcParams屬性字典
  • 想要它正常工作,在matplotlibrc配置檔案中需要設定text.markup = "tex"。
  • 如果你希望圖表中所有的文字(包括座標軸刻度標記)都是LaTeX'd,需要在matplotlibrc中設定text.usetex = True。如果你使用LaTeX撰寫論文,那麼這一點對於使圖表和論文中其餘部分保持一致是很有用的。
  • 在matplotlib中使用中文字串時記住要用unicode格式,例如:u''測試中文顯示''