這個教程也很不錯,http://reverland.org/python/2012/09/07/matplotlib-tutorial/
也可以參考官網的Gallery,http://matplotlib.org/gallery.html
做數據分析,首先是要熟悉和理解數據,所以掌握一個趁手的可視化工具是非常重要的,否則對數據連個基本的感性認識都沒有,如何進行下一步的design
Getting Started with Matplotlib
先看個簡單的例子,plot,即畫線
畫線,需要給出線上的點的坐標,然后Matplotlib會自動將點連成線
In [2]: x = range(6)
In [3]: plt.plot(x, [xi**2 for xi in x])
可以看到plot的參數是兩個list,分布表示x軸和y軸的坐標點的list
可以看到這里的線不是很平滑,是因為range的產生的點粒度比較粗,並且使用list comprehension來產生y值
所以這里盡量使用Numpy的arange(x, y, z)函數
好處是粒度可以更小,而且關鍵是返回的是Numpy的Array,可以直接進行向量或矩陣運算,如下
In [3]: x = np.arange(1, 5)
In [4]: plt.plot(x, x*1.5, x, x*3.0, x, x/3.0)
可以用plot畫多條線
Grid, axes, and labels
打開網格
In [5]: plt.grid(True)
默認會自動產生X和Y軸上的取值范圍,比如上面的圖,
In [5]: plt.axis() # shows the current axis limits values
Out[5]: (1.0, 4.0, 0.0, 12.0)
分別表示,[xmin, xmax, ymin, ymax],所以看上圖x軸是從1到4,y軸是從0到12
改變取值范圍,
In [6]: plt.axis([0, 5, -1, 13]) # set new axes limits
還能給x和y軸加上lable說明,
In [2]: plt.plot([1, 3, 2, 4])
In [3]: plt.xlabel('This is the X axis')
In [4]: plt.ylabel('This is the Y axis')
Titles and legends
給整個圖加上title
In [2]: plt.plot([1, 3, 2, 4])
In [3]: plt.title('Simple plot')
還可以給每條線增加圖示,legend
In [3]: x = np.arange(1, 5)
In [4]: plt.plot(x, x*1.5, label='Normal')
In [5]: plt.plot(x, x*3.0, label='Fast')
In [6]: plt.plot(x, x/3.0, label='Slow')
In [7]: plt.legend()
指定每條線的label,然后調用legend()會自動顯示圖示
可以看到這個圖示的位置不是很好,擋住圖,可以通過參數指定位置
legend(loc='upper left')
loc可以選取的值,其中best,是自動找到最好的位置
Saving plots to a file
最簡單,使用默認設置
plt.savefig('plot123.png')
其中兩個設置可以決定圖片大小,figure size and the DPI
In [1]: import matplotlib as mpl
In [2]: mpl.rcParams['figure.figsize']
Out[2]: [8.0, 6.0]
In [3]: mpl.rcParams['savefig.dpi']
Out[3]: 100
an 8x6 inches figure with 100 DPI results in an 800x600 pixels image,這就是默認值
In [4]: plt.savefig('plot123_2.png', dpi=200)
這樣圖的分辨率,變為1600×1200
Decorate Graphs with Plot Styles
Markers and line styles
上面畫的線都是一樣的,其實我們可以畫出各種不同的線
Marker就是指形成線的那些點
plot() supports an optional third argument that contains a format string for each pair of X, Y arguments in the form of:
plt.plot(X, Y, '<format>', ...)
plot通過第三個string參數可以用來指定,Colors,Line styles,Marker styles
線的顏色,
線的style,
Marker的style
可以用string format單獨或混合的表示所有的style,
In [3]: y = np.arange(1, 3, 0.3)
In [4]: plt.plot(y, 'cx--', y+1, 'mo:', y+2, 'kp-.');

比如第一條線,c表示cyan青色,x表示marker style為x,--表示line style
一般用string format已經足夠,但也可以用具體的keyword參數進行更多的個性化
Handling X and Y ticks
前面X和Y軸上的ticks是自動生成的,這個也是可以通過xticks和yticks函數個性化定制的
The arguments (in the form of lists) that we can pass to the function are:
• Locations of the ticks
• Labels to draw at these locations (if necessary)
可以定義,每個tick的location和相應的label(可選,不指定默認顯示location)
In [2]: x = [5, 3, 7, 2, 4, 1]
In [3]: plt.plot(x);
In [4]: plt.xticks(range(len(x)), ['a', 'b', 'c', 'd', 'e', 'f']);
In [5]: plt.yticks(range(1, 8, 2));
對x軸同時指定location和label
對y軸只是指定location
Plot types
上面介紹了很多,都是以plot作為例子,matplotlib還提供了很多其他類型的圖
作者這張圖很贊,描述所有圖的用法
Histogram charts
直方圖是用來離散的統計數據分布的,會把整個數據集,根據取值范圍,分成若干類,稱為bins
然后統計中每個bin中的數據個數
In [3]: y = np.random.randn(1000)
In [4]: plt.hist(y);
In [5]: plt.show()
hist默認是分為10類,即bins=10, 上圖就是把取值[-4,4]上的1000個隨機數,分成10個bins,統計每個的數據個數
可以看出這個隨機函數是典型的正態分布
我們可以改變bins的值,
In [6]: plt.hist(y, 25);
如圖是,分成25個bins
Error bar charts
In [3]: x = np.arange(0, 4, 0.2)
In [4]: y = np.exp(-x)
In [5]: e1 = 0.1 * np.abs(np.random.randn(len(y)))
In [8]: e2 = 0.1 * np.abs(np.random.randn(len(y)))
In [9]: plt.errorbar(x, y, yerr=e1, xerr=e2, fmt='.-', capsize=0);
畫出每個點的同時,畫出每個點上的誤差范圍
還能畫出非對稱的誤差,
In [11]: plt.errorbar(x, y, yerr=[e1, e2], fmt='.-');
Bar charts
plt.bar([1, 2, 3], [3, 2, 5]);
對於bar,需要設定3個參數
左起始坐標,高度,寬度(可選,默認0.8)
所以上面的例子,指定起始點和高度參數
好,看個復雜的例子,bar圖一般用於比較多個數據值
In [3]: data1 = 10*np.random.rand(5)
In [4]: data2 = 10*np.random.rand(5)
In [5]: data3 = 10*np.random.rand(5)
In [6]: e2 = 0.5 * np.abs(np.random.randn(len(data2)))
In [7]: locs = np.arange(1, len(data1)+1)
In [8]: width = 0.27
In [9]: plt.bar(locs, data1, width=width);
In [10]: plt.bar(locs+width, data2, yerr=e2, width=width, color='red');
In [11]: plt.bar(locs+2*width, data3, width=width, color='green') ;
In [12]: plt.xticks(locs + width*1.5, locs);
需要學習的是,如何指定多個bar的起始位置,后一個bar的loc = 前一個bar的loc + width
如何設置ticks的label,讓它在一組bars的中間位置,locs + width*1.5
Pie charts
餅圖很好理解,表示成分
In [2]: plt.figure(figsize=(3,3));
In [3]: x = [45, 35, 20]
In [4]: labels = ['Cats', 'Dogs', 'Fishes']
In [5]: plt.pie(x, labels=labels);
來個復雜的,
增加explode,即突出某些wedges,可以設置explode來增加offset the wedge from the center of the pie, 即radius fraction
0表示不分離,越大表示離pie center越遠,需要顯式指定每個wedges的explode
增加autopct,即在wedges上顯示出具體的比例
In [2]: plt.figure(figsize=(3,3));
In [3]: x = [4, 9, 21, 55, 30, 18]
In [4]: labels = ['Swiss', 'Austria', 'Spain', 'Italy', 'France', 'Benelux']
In [5]: explode = [0.2, 0.1, 0, 0, 0.1, 0]
In [6]: plt.pie(x, labels=labels, explode=explode, autopct='%1.1f%%');
Scatter plots
只畫點,不連線,用來描述兩個變量之間的關系,比如在進行數據擬合之前,看看變量間是線性還是非線性
In [3]: x = np.random.randn(1000)
In [4]: y = np.random.randn(1000)
In [5]: plt.scatter(x, y);
通過s來指定size,c來指定color,
marker來指定點的形狀
In [7]: size = 50*np.random.randn(1000)
In [8]: colors = np.random.rand(1000)
In [9]: plt.scatter(x, y, s=size, c=colors);

Text inside figure, annotations, and arrows
用於添加注解,
增加text很簡單,坐標x,y,內容
plt.text(x, y, text)
例子,
In [3]: x = np.arange(0, 2*np.pi, .01)
In [4]: y = np.sin(x)
In [5]: plt.plot(x, y);
In [6]: plt.text(0.1, -0.04, 'sin(0)=0');
annotate,便於增加注釋
參數,
xy,需要添加注釋的坐標
xytext,注釋本身的坐標
arrowprops,箭頭的類型和屬性
In [2]: y = [13, 11, 13, 12, 13, 10, 30, 12, 11, 13, 12, 12, 12, 11,12]
In [3]: plt.plot(y);
In [4]: plt.ylim(ymax=35); 增大y的空間,否則注釋放不下
In [5]: plt.annotate('this spot must really\nmean something',
xy=(6, 30), xytext=(8, 31.5), arrowprops=dict(facecolor='black', shrink=0.05));
明顯這個箭頭比較丑,箭頭可以有很多種
In [2]: plt.axis([0, 10, 0, 20]);
In [3]: arrstyles = ['-', '->', '-[', '<-', '<->', 'fancy', 'simple','wedge']
In [4]: for i, style in enumerate(arrstyles):
plt.annotate(style, xytext=(1, 2+2*i), xy=(4, 1+2*i), arrowprops=dict(arrowstyle=style));
In [5]: connstyles=["arc", "arc,angleA=10,armA=30,rad=15", "arc3,rad=.2", "arc3,rad=-.2", "angle", "angle3"]
In [6]: for i, style in enumerate(connstyles):
plt.annotate("", xytext=(6, 2+2*i), xy=(8, 1+2*i), arrowprops=dict(arrowstyle='->', connectionstyle=style));
Subplots
上面matplotlib,默認會幫我們創建figure和subplot
fig = plt.figure()
ax = fig.add_subplot(111)
其實我們可以顯式的創建,這樣的好處是我們可以在一個figure中畫多個subplot
其中subplot的參數,
fig.add_subplot(numrows, numcols, fignum)
- numrows represents the number of rows of subplots to prepare
- numcols represents the number of columns of subplots to prepare
- fignum varies from 1 to numrows*numcols and specifies the current subplot (the one used now)
我們會產生numrows×numcols個subplot,fignum表示編號
In [2]: fig = plt.figure()
In [3]: ax1 = fig.add_subplot(211)
In [4]: ax1.plot([1, 2, 3], [1, 2, 3]);
In [5]: ax2 = fig.add_subplot(212)
In [6]: ax2.plot([1, 2, 3], [3, 2, 1]);
Plotting dates
日期比較長,直接畫在坐標軸上,沒法看
具體看下如何畫?
產生x軸數據,利用mpl.dates.drange產生x軸坐標
import matplotlib as mpl
In [7]: date2_1 = dt.datetime(2008, 9, 23)
In [8]: date2_2 = dt.datetime(2008, 10, 3)
In [9]: delta2 = dt.timedelta(days=1)
In [10]: dates2 = mpl.dates.drange(date2_1, date2_2, delta2)
隨機產生y軸坐標,畫出polt圖
In [11]: y2 = np.random.rand(len(dates2))
In [12]: ax2.plot_date(dates2, y2, linestyle='-');
關鍵步驟來了,我們要設置xaxis的locator和formatter來顯示時間
首先設置formatter,
In [13]: dateFmt = mpl.dates.DateFormatter('%Y-%m-%d')
In [14]: ax2.xaxis.set_major_formatter(dateFmt)
再設置locator,
In [15]: daysLoc = mpl.dates.DayLocator()
In [16]: hoursLoc = mpl.dates.HourLocator(interval=6)
In [17]: ax2.xaxis.set_major_locator(daysLoc)
In [18]: ax2.xaxis.set_minor_locator(hoursLoc)
注意這里major和minor,major就是大的tick,minor是比較小的tick(默認是null)
比如date是大的tick,但是想看的細點,所以再設個hour的tick,但是畫24個太多了,所以interval=6,只畫4個
而formatter只是設置major的,所以minor的是沒有label的
再看個例子,
產生x軸坐標,y軸坐標,畫出plot
In [22]: date1_1 = dt.datetime(2008, 9, 23)
In [23]: date1_2 = dt.datetime(2009, 2, 16)
In [24]: delta1 = dt.timedelta(days=10)
In [25]: dates1 = mpl.dates.drange(date1_1, date1_2, delta1)
In [26]: y1 = np.random.rand(len(dates1))
In [27]: ax1.plot_date(dates1, y1, linestyle='-');
設置locator
major的是Month,minor的是week
In [28]: monthsLoc = mpl.dates.MonthLocator()
In [29]: weeksLoc = mpl.dates.WeekdayLocator()
In [30]: ax1.xaxis.set_major_locator(monthsLoc)
In [31]: ax1.xaxis.set_minor_locator(weeksLoc)
設置Formatter
In [32]: monthsFmt = mpl.dates.DateFormatter('%b')
In [33]: ax1.xaxis.set_major_formatter(monthsFmt)
Using LaTeX formatting
這個略diao
the start and the end of a mathtext string is $
在python raw string需要r‘’,表示不轉義
直接看例子,
In [6]: ax.text(2, 8, r"$ \mu \alpha \tau \pi \lambda \omega \tau \lambda \iota \beta $");
In [7]: ax.text(2, 6, r"$ \lim_{x \rightarrow 0} \frac{1}{x} $");
In [8]: ax.text(2, 4, r"$ a \ \leq \ b \ \leq \ c \ \Rightarrow \ a \ \leq \ c$");
In [9]: ax.text(2, 2, r"$ \sum_{i=1}^{\infty}\ x_i^2$");
In [10]: ax.text(4, 8, r"$ \sin(0) = \cos(\frac{\pi}{2})$");
In [11]: ax.text(4, 6, r"$ \sqrt[3]{x} = \sqrt{y}$");
In [12]: ax.text(4, 4, r"$ \neg (a \wedge b) \Leftrightarrow \neg a \vee \neg b$");
In [13]: ax.text(4, 2, r"$ \int_a^b f(x)dx$");