《利用python進行數據分析》讀書筆記--第八章 繪圖和可視化


python有許多可視化工具,本書主要講解matplotlib。matplotlib是用於創建出版質量圖表的桌面繪圖包(主要是2D方面)。matplotlib的目的是為了構建一個MATLAB式的繪圖接口。本書中的大部分圖都是用它生成的。除了圖形界面顯示,還可以把圖片保存為pdf、svg、jpg、png、gif等形式。

1、matplotlib API入門

Ipython可以用close()關閉界面。

Figure和Subplot

matplotlib的圖像都位於Figure對象中。用plt.figure創建一個新的Figure。

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
'''
#plt.plot(np.arange(10))
fig = plt.figure()
#plt.show()
#figsize 有一些重要的選項,特別是figsize,規定的是圖片保存到磁盤時具有一定大小的縱橫比。
#plt.gcf()即可得到當前Figure的引用
ax1 = fig.add_subplot(2,2,1)
ax2 = fig.add_subplot(2,2,2)
ax3 = fig.add_subplot(2,2,3)
plt.plot(np.random.randn(50).cumsum(),'k--')


#fig.add_subplot 返回的對象是AxesSubplot對象,下面調用就可以了
_ = ax1.hist(np.random.randn(100),bins = 20,color = 'k',alpha = 0.3)
ax2.scatter(np.arange(30),np.arange(30) + 3 * np.random.randn(30))
plt.show()
'''
#由於Figure 和 subplot是一件非常常見的任務,於是出現了更為方便的方法(plt.subplots ),它可以創建一個新的Figure,
#並返回一個含有已創建的subplot對象的Numpy數組
fig,axes = plt.subplots(2,3)

#print fig
print axes[0][0]
#axes[0][0].hist(np.random.randn(100),bins = 20,color = 'k',alpha = 0.3)
plt.show()
#這是非常實用的,因為可以輕松地對axes數組進行索引,就好像一個是一個二維數組一樣,例如
#axes[0,1].還可以通過sharex和sharey指定subplot具有相同的x軸和y軸。在比較相同范圍的數據時,這是
#非常實用的,否則matplotlib會自動縮放各圖表的界限。

看一下subplots的作用:

image

pyplot.subplots的選項還有:

image

上面的**fig_k可以有很多的參數,文檔中有更多的內容。

調整subplot周圍的間距

默認情況下,matplotlib會在subplot外圍留下一定的邊距,並在subplot之間留下一定的間距。間距和圖像的高度和寬度有關,會自動調整。利用Figure的subplots——adjust方法可以修改間距,因此,它是一個頂級函數。

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt

subplots_adjust(left = None,bottom = None,right = None,top = None,wspace = None,hspace = None)
#wspace和space用於控制寬度和高度的百分比,可以用做subplot之間的間距,下面是個例子:
'''
fig,ax = plt.subplots(2,2,sharex = True,sharey = True)
for i in range(2):
     for j in range(2):
          ax[i,j].hist(np.random.randn(500),bins = 50,color = 'k',alpha = 0.5)
plt.subplots_adjust(wspace = 0.5,hspace = 0.5)
plt.show()
#matplotlib不會檢查標簽的重疊(確實是這樣)。
# -*- encoding: UTF-8 -*- 
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt



fig,ax = plt.subplots(2,2)

#cecece是白色……
ax[0,0].plot(np.arange(10),linestyle = '--',color = '#CECECE')

#線上面還可以添加一些標記(marker),以強調實際的數據點。由於matplotlib創建的是連續的線形圖,因此有時可能不太容易看到真實點的位置,標記可以放到格式字符串中,但是標記類型和線性必須在顏色的后面
ax[0,1].plot(np.random.randn(30).cumsum(),'ko--')
ax[1,0].plot(np.random.randn(30).cumsum(),color = 'k',linestyle = '--',marker = 'o')
#在線型圖中,非實際數據點默認是按照線性插值的,可以通過drawstyle選項修改這一點。
data = np.random.randn(30).cumsum()
ax[1,1].plot(data,'ko--')
ax[1,1].plot(data,'k--',drawstyle = 'steps-post')
plt.show()

注意上面的drawstyle選項可以規定點與點之間的連接方式,或者說是插值方式,結果為:

image

設置標題、軸標簽、刻度以及刻度標簽

# -*- encoding: UTF-8 -*- 
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import numpy.random as npr

fig = plt.figure()
ax = fig.add_subplot(1,1,1)
ax.plot(npr.randn(1000).cumsum())

#要想修改x的刻度,最簡單的方法就是使用set_xticks和set_xticklabels.前者告訴matplotlib將
#刻度放在數據范圍中的哪些位置,默認情況下,這些位置就是刻度標簽。但是可以使用set_xticklabels將#任何其他的值用作標簽
ticks = ax.set_xticks([0,250,500,700,900,1000])
#下面的totation是規定旋轉角度
labels = ax.set_xticklabels(['a','b','c','d','e','f'],rotation = 30,fontsize = 'small')
#可以為x軸設置名稱
ax.set_xlabel('Stages')

plt.show()

image

圖例

# -*- encoding: UTF-8 -*- 
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import numpy.random as npr
from datetime import datetime

#添加圖例
fig = plt.figure()
ax = fig.add_subplot(1,1,1)
ax.plot(npr.randn(1000).cumsum(),'k',label = 'one')
ax.plot(npr.randn(1000).cumsum(),'k--',label = 'two')
ax.plot(npr.randn(1000).cumsum(),'k.',label = 'three')
ax.legend(loc = 'best')
plt.show()

image

注解與繪圖

# -*- encoding: UTF-8 -*- 
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import numpy.random as npr
from datetime import datetime


fig = plt.figure()
ax = fig.add_subplot(1,1,1)

data = pd.read_csv('E:\\spx.csv',index_col = 0,parse_dates = True)
spx = data['SPX']
spx.plot(ax = ax,style = 'k-')

crisis_data = [
(datetime(2007,10,11),'Peak of bull market'),
(datetime(2008,3,12),'Bear Stearns Fails'),
(datetime(2008,9,15),'Lehman Bankruptcy')
]

for date,label in crisis_data:
    ax.annotate(label,xy = (date,spx.asof(date) + 50),
        xytext = (date,spx.asof(date) + 200),
        arrowprops = dict(facecolor = 'black'),
        horizontalalignment = 'left',verticalalignment = 'top')
ax.set_xlim(['1/1/2007','1/1/2011'])
ax.set_ylim([600,1800])

ax.set_title('Important dates in 2008-2009 finacial crisis')
plt.show()
#更多關於注解的示例,請看文檔

#圖形的繪制要麻煩些,有一些常見的圖形的對象,這些對象成為塊(patch)
#如Rectangle 和 Circle,完整的塊位於matplotlib.patches
#要繪制圖形,需要創建一個塊對象shp,然后通過ax.add_patch(shp)將其添加到subplot中

fig = plt.figure()
ax = fig.add_subplot(1,1,1)

rect = plt.Rectangle((0.2,0.75),0.4,0.15,color = 'k',alpha = 0.3)
circ = plt.Circle((0.7,0.2),0.15,color = 'b',alpha = 0.3)
pgon = plt.Polygon([[0.15,0.15],[0.35,0.4],[0.2,0.6]],color = 'g',alpha = 0.5)

ax.add_patch(rect)
ax.add_patch(circ)
ax.add_patch(pgon)

plt.show()

image

image

將圖表保存到文件

# -*- encoding: UTF-8 -*- 
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import numpy.random as npr
from datetime import datetime
from io import StringIO

#將圖標保存到文件
#savefig函數可以保存圖形文件,不同的擴展名保存為不同的格式
fig = plt.figure()
ax = fig.add_subplot(1,1,1)

rect = plt.Rectangle((0.2,0.75),0.4,0.15,color = 'k',alpha = 0.3)
circ = plt.Circle((0.7,0.2),0.15,color = 'b',alpha = 0.3)
pgon = plt.Polygon([[0.15,0.15],[0.35,0.4],[0.2,0.6]],color = 'g',alpha = 0.5)

ax.add_patch(rect)
ax.add_patch(circ)
ax.add_patch(pgon)

#注意下面的dpi(每英寸點數)和bbox_inches(可以剪除當前圖標周圍的空白部分)(確實有效)
#plt.savefig('pic.jpg',dpi = 100,bbox_inches = 'tight')

#不一定save到文件中,也可以寫入任何文件型對象,比如StringIO:

buffer = StringIO()
plt.savefig(buffer)
plot_data = buffer.getvalue()

#這對Web上提供動態生成的圖片是很實用的

#plt.show()

savefig的一些選項:

image

matplotlib配置

matplotlib的一些屬性是可以設置的,比如圖像大小、subplot邊距、配色方案、字體大小、網格類型等。有兩種方式進行操作。第一種是Python變成方式,即利用rc方法。比如:

plt.rc('figure',figsize = (10,10))

rc的第一個參數是希望自定義的對象,比如‘figure’、‘axes’、‘xtick’、‘ytick’、‘grid’、‘legend’等。其后可以跟上一系列的關鍵字參數。最簡單的就是寫成一個字典:

font_options = {'family':'monospace',
                         'weight':'bold',
                         'size':'small'}
plt.rc('font',**font_options)

matplotlibrc是配置文件,定義好以后每次加載就會用設置的參數。

2、pandas中的繪圖函數

matplotlib是一種比較低級的工具,需要將各種組件組合好:數據展示(線型圖、柱狀圖等)、圖例、標題、刻度標簽以及注解。這是因為制作一張圖表一般需要用到多個對象。在pandas中,會省事不少。pandas能夠利用DataFrame的對象特點創建標准圖表的高級繪圖方法。作者說pandas在線文檔時最好的學習工具,書上的代碼可能過時了。

線型圖

#-*- encoding:utf-8 -*-
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from pandas import Series,DataFrame

s = Series(np.random.randn(10).cumsum(),index = np.arange(0,100,10))
#該Series對象的索引會被傳給matplotlib,並繪制X軸。
#可以用use_index = False 禁用該功能
s.plot(use_index = False)

#X軸的刻度和界限可以通過xticks和xlim選項進行調節,Y軸通過xticks和ylim調節

plt.show()

#pandas的大部分方法都有一個可選的ax參數,可以是一個subplot對象。這可以
#使在網格中更為靈活地處理subplot的位置。
#DataFrame的plot方法會在一個subplot中為各列繪制線型圖,並自動添加圖例
df = DataFrame(np.random.randn(10,4).cumsum(0),
    columns = ['A','B','C','D'],
    index = np.arange(0,100,10))
df.plot()
plt.show()

image

image

下面把參數貼一下:

image

image

DataFrame還有一些對列進行處理的參數:

image

自下面開始就有一些專門的圖形,繪制的時候可以與R語言進行對比:http://www.cnblogs.com/batteryhp/p/4733474.html

柱狀圖

#-*- encoding:utf-8 -*-
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from pandas import Series,DataFrame


#生成的線形圖中代碼加上kind = ‘bar’(垂直柱圖) 或者 (水平)kind = ‘barh’(水平柱圖)
#Series和DataFrame的索引被用作X(bar)或者Y(barh)的刻度

fig,axes = plt.subplots(2,1)
data = Series(np.random.randn(16),index = list('abcdefghijklmnop'))

data.plot(kind = 'barh',ax = axes[0],color = 'k',alpha = 0.7)
data.plot(kind = 'bar',ax = axes[1],color = 'k',alpha = 0.7)

#DataFrame會按照行對數據進行分組
df = DataFrame(np.random.randn(6,4),index = ['one','two','three','four','five','six'],
    columns = pd.Index(['A','B','C','D'],name = 'Genus')) 
#注意這里的name會被用作圖例的標題,因為,這本來就是列的名字
print df
df.plot(kind = 'bar')
plt.show()
#這里的stacked是標明畫累計柱圖
df.plot(kind = 'bar',stacked = True,alpha = 0.5)
plt.show()

#Series的value_counts可以用來顯示Series中各值的頻數(實驗證明)
s = Series([1,2,2,3,4,4,4,5,5,5])
s.value_counts().plot(kind = 'bar')
plt.show()

image

image

image

image

下面看一個例子:

#-*- encoding:utf-8 -*-
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from pandas import Series,DataFrame

#下面是一個例子:做一張堆積柱狀圖來顯示每天各種聚會規模的數據點百分比
tips = pd.read_csv('E:\\tips.csv')
party_counts = pd.crosstab(tips.day,tips.size)
print party_counts
party_counts = party_counts.ix[:,2:5]
#然后進行歸一化是各行和為1
party_pcts = party_counts.div(party_counts.sum(1).astype(float),axis = 0)
print party_pcts
party_pcts.plot(kind = 'bar',stacked = True)
plt.show()

image

直方圖和密度圖

#-*- encoding:utf-8 -*-
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from pandas import Series,DataFrame
#繪制小費百分比直方圖
tips = pd.read_csv('E:\\tips.csv')
tips['tip_pct'] = tips['tip'] / tips['total_bill']
#bins規定一共分多少個組
tips['tip_pct'].hist(bins = 50)
plt.show()

#與此相關的是密度圖:他是通過計算“可能會產生觀測數據的連續概率分布的估計”
#而產生的。一般的過程將該分布金思維一組核(諸如正態之類的較為簡單的分布)。
#此時的密度圖稱為KDE圖。kind = ‘kde’即可。
tips['tip_pct'].plot(kind = 'kde')
plt.show()

#顯然,直方圖和密度圖經常會在一起出現
comp1 = np.random.normal(0,1,size = 200)
comp2 = np.random.normal(10,2,size = 200)
values = Series(np.concatenate([comp1,comp2]))
print values
values.hist(bins = 100,alpha = 0.3,color = 'k',normed = True)
values.plot(kind = 'kde',style = 'k--')
plt.show()

image

image

image

散布圖

散布圖(scantter plot)是觀察兩個一維數據序列之間的關系的有效手段。matplotlib中的scantter方法是繪制散布圖的主要方法。

#-*- encoding:utf-8 -*-
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from pandas import Series,DataFrame

#下面加載macrodata中的數據集,選擇其中幾列並計算對數差
macro = pd.read_csv('E:\\macrodata.csv')
data = macro[['cpi','m1','tbilrate','unemp']]
#這里的diff函數是用來計算相鄰兩數只差,對每一列,后一個數減前一個數
trans_data = np.log(data).diff().dropna()
#print np.log(data).head()
#print np.log(data).diff().head()
print trans_data.head()

plt.scatter(trans_data['m1'],trans_data['unemp'])
plt.title('Changes in log %s vs. log %s'%('m1','unemp'))
plt.show()
#畫散布圖矩陣式很有意義的pandas提供了scantter_matrix函數來創建散步矩陣
#關於 diagonal 參數,是為了不讓對角線上的圖形(自己和自己的散布圖)顯示為一條直線而設置的關於這種數據的某些圖形顯示
#比如 diagonal = 'kde'就是畫密度圖且核為kde,若diagonal='hist',則為直方圖
pd.scatter_matrix(trans_data,diagonal = 'kde',color = 'k',alpha = 0.3)
pd.scatter_matrix(trans_data,diagonal = 'hist',color = 'k',alpha = 0.3)
plt.show()

image

image

image

繪制地圖:圖形化顯示海地地震危機數據

這是一個例子。

#-*- encoding:utf-8 -*-
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from pandas import Series,DataFrame
from mpl_toolkits.basemap import Basemap

#下面的例子應該是比較綜合的
data = pd.read_csv('E:\\Haiti.csv')
#print data
#下面處理一下數據,下面的為日期,緯度、經度
#print data[['INCIDENT DATE','LATITUDE','LONGITUDE']][:10]
#print data['CATEGORY'][:6]   #這些代表消息的類型
#數據中很有可能有異常值、缺失值,下面看一下
#print data.describe()
#清除錯誤信息並移除缺失分類信息是“一件簡單的事情”
data = data[(data.LATITUDE > 18) & (data.LATITUDE < 20) & (data.LONGITUDE > -75) &
           (data.LONGITUDE < -70) & data.CATEGORY.notnull()]

#我們想根據分類對數據做一些分析或者圖形化工作,但是各個分類字段中可能含有多個分類。此外,各個分類信息
#不僅有一個編碼,還有一個英語(法語)名稱。因此需要對數據進行規整化處理。下面編寫兩(三)個
#函數,一個用於獲取所有分類的列表,一個用於將各個分類信息拆分為編碼和英語明名稱

#sptrip 是刪除空白字符,'\n'等;注意作者這種隱式循環寫法
def to_cat_list(catstr):
    stripped = (x.strip() for x in catstr.split(','))
    return [x for x in stripped if x]
def get_all_categoties(cat_series):
    cat_sets = (set(to_cat_list(x)) for x in cat_series)
    return sorted(set.union(*cat_sets))
def get_english(cat):
    code,names = cat.split('.')
    if '|' in names:
        names = names.split('|')[1]
    return code,names.strip()

#下面進行一下ceshi
#print get_english('2.Urgences logistiques | Vital Lines')
#接下來做了一個將編碼跟名稱映射起來的字典,這是因為我們等會要用編碼進行分析。
#下面將所有組合弄出來
all_cats = get_all_categoties(data.CATEGORY)
#print data.CATEGORY[:10]
#print all_cats
#生成器表達式
#生成字典
english_mapping = dict(get_english(x) for x in all_cats)
#print english_mapping['2a']
#print english_mapping['6c']
#根據分類選取記錄的方式有很多,其中之一就是添加指標(或者啞變量)列,每個分類一列。
#為此,首先抽取出唯一的分類編碼,並構造一個全零DataFrame(列為分類編碼,索引跟data的索引一樣)
def get_code(seq):
    return [x.split('.')[0] for x in seq if x]
#下面是將所有的key取出來
all_codes = get_code(all_cats)
#print all_codes
code_index = pd.Index(np.unique(all_codes))
#print code_index
dummy_frame = DataFrame(np.zeros((len(data),len(code_index))),index = data.index,columns = code_index)
#print len(data)
#print dummy_frame.ix[:,:6]
#下面將各行中適當的項設置為1,然后再與data進行連接:

for row,cat in zip(data.index,data.CATEGORY):
    codes = get_code(to_cat_list(cat))
    dummy_frame.ix[row,codes] = 1
#添加前綴,並且合並一下
data = data.join(dummy_frame.add_prefix('category_'))
#print data
#接下來開始畫圖吧,我們希望把數據繪制在海地的地圖上。basemap數據集是matplotloib的一個插件
#使得能夠用Python在地圖上繪制2D數據。basemap提供了許多不同的地球投影以及一種將地球上的經緯度
#坐標投影轉換為二維matplotlib圖的方式。
#“經過一遍又一遍的嘗試”,作者編寫了下面的函數,繪制出一張簡單的黑白地圖。

def basic_haiti_map(ax = None,lllat = 17.25,urlat = 20.25,lllon = -75,urlon = -71):
    #創建極球面投影的Basemap實例。
    m  = Basemap(ax = ax,projection = 'stere',
        lon_0 = (urlon + lllon) / 2,
        lat_0 = (urlat + lllat) / 2,
        llcrnrlat = lllat,urcrnrlat = urlat,
        llcrnrlon = lllon,urcrnrlon = urlon,
        resolution = 'f' )

由於window下安裝geos不成功,這部分等ubuntu裝好了再接着寫。

4、Python圖形化工具生態系統

介紹幾個其他的繪圖工具。

Chaco

特點:靜態圖 + 交互圖形,非常適合用復雜的圖形化方法表示數據的內部關系。對交互支持的好的多,交互式GUI是個不錯選擇。

mayavi

這是一個基於開源C++圖形庫VTK的3D圖形工具包。可以集成到Ipython交互使用。

其他庫

其他庫或者應用還有:PyQwt、Veusz、gnuplotpy、biggles等,大部庫都在向基於Web的技術發展,並逐漸遠離桌面圖形技術。

圖形化工具的未來

基於Web技術(如Javascript)的圖形化是必然的發展趨勢,現在已經有不少了,higncharts等。

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM