在本系列的上篇文章里,我們從Matplotlib的基礎(chǔ)可視化框架開始亏镰,逐步畫出折線圖腊满、柱狀圖等基礎(chǔ)圖表套么,通過對(duì)坐標(biāo)軸標(biāo)簽、標(biāo)題文本等的精細(xì)調(diào)節(jié)畫出信息更明確豐富的可視圖碳蛋,也實(shí)踐了雙軸圖及子圖胚泌,最后看了下極坐標(biāo)系下繪圖的效果。本篇繼續(xù)探索Matplotlib的強(qiáng)悍可視化能力肃弟。
Matplotlib動(dòng)態(tài)可視化
計(jì)算機(jī)及通信技術(shù)的發(fā)展極大豐富了多媒體內(nèi)容的發(fā)展诸迟,文不如圖、圖不如動(dòng)圖愕乎;BI近些年也逐漸發(fā)展阵苇,人們已不滿足于看靜態(tài)的圖表。短視頻的火熱也給了動(dòng)態(tài)圖更多的發(fā)展空間感论。動(dòng)態(tài)圖和交互圖表能更生動(dòng)地表現(xiàn)數(shù)據(jù)變化及數(shù)據(jù)聯(lián)系绅项,傳達(dá)更多的信息。
插入排序的動(dòng)態(tài)展現(xiàn)
生動(dòng)的動(dòng)畫有助于我們理解算法比肄。通過Matplotlib其實(shí)我們也可以繪制動(dòng)態(tài)的算法關(guān)鍵過程快耿,下面拿插入排序作為例子看Matplotlib如何繪制動(dòng)態(tài)圖。
玩撲克時(shí)的抓牌環(huán)節(jié)很契合插入排序的執(zhí)行過程芳绩。其思路是:保持手中的已有的牌始終有序掀亥,當(dāng)抓到一張新牌時(shí),按照牌面的點(diǎn)數(shù)妥色,將其插入合適的位置搪花。怎么去判斷該插入的位置呢?我們通常的做法就是從左到右或從右到左掃描以找到當(dāng)前牌的位置嘹害,初始化時(shí)我們可以新建一個(gè)數(shù)組作為始終有序的結(jié)果集撮竿,也可以直接用原來(lái)的數(shù)組空間進(jìn)行交換操作,整體時(shí)間復(fù)雜度是O(n^2)笔呀。將這一過程翻譯為Python代碼如下:
def isort(lst):
n=len(lst) #直接用原數(shù)組進(jìn)行排序
for i in range(1,n):
x=lst[i] #當(dāng)前值
j=i-1
while j>=0 and x<lst[j]: #從右往左找插入的位置
lst[j+1]=lst[j] #將比x大的牌往后移一位
j-=1
lst[j+1]=x #換牌
return lst
為了直觀展示插入排序的關(guān)鍵步驟幢踏,我們將每做一次插入的結(jié)果保存下來(lái)然后用Matplotlib畫成一系列柱狀圖。通過matplotlib.animation
繪制成動(dòng)態(tài)圖许师。
首先改一下排序函數(shù)房蝉,增加一個(gè)變量保存每次到插入步驟時(shí)的數(shù)組僚匆,因?yàn)椴皇沁f歸的排序代碼,在for循環(huán)前用一個(gè)變量w保存關(guān)鍵結(jié)果搭幻,基于這些中間結(jié)果花一系列的圖白热,再連成動(dòng)態(tài)GIF圖,代碼如下粗卜,關(guān)鍵步驟都有注釋屋确。
def isort(lst): #插入排序代碼
n=len(lst)
w={0:{'v':lst.copy(),'j':-1}} #保存j以確定到哪里插入
for i in range(1,n):
x=lst[i] #當(dāng)前值
j=i-1
while j>=0 and x<lst[j]: #x比j處值小時(shí),繼續(xù)向左
lst[j+1]=lst[j] #將比x大的牌往后移一位
j-=1
lst[j+1]=x #換牌
w[i]={'v':lst.copy(),'j':j}
#print(xs,i,j,x)
return w #不需要lst
import matplotlib.animation as anm #引入接口
fig,ax=plt.subplots()
def draw_bar(i): #每傳入一個(gè)i畫一個(gè)柱狀圖
w=wk[i]
nw=len(w['v'])
ax.clear() #清空之前畫的元素
c1=[]
for j in range(nw): #調(diào)節(jié)柱的顏色
if j<i:
c1.append('#1EAFAE')
elif i==nw-1:
c1.append('#1EAFAE')
elif j==i:
c1.append('#BA5C25')
else:
c1.append('#69FFFF')
if i!=nw-1 and w['j']+1!=i: #所交換的位置
c1[w['j']+1]='#FFA069'
rs=ax.bar(range(nw),w['v'],color=c1)
ax.set_ylim(0,8)
ax.set_title('Insert Sorted Animation')
c=0
for r in rs: #給每個(gè)柱加文本標(biāo)簽
ax.annotate('{0}'.format(w['v'][c]),xy=(r.get_x()+r.get_width()/2,r.get_height()+0.1))
c+=1
#繪制動(dòng)圖
amt=anm.FuncAnimation(fig,draw_bar,frames=range(6),interval=600)
amt.save('insert-sorted-animation-1.gif')
拿一個(gè)未排序數(shù)組進(jìn)行測(cè)試续扔,效果如下:
(其中青色表示已排序元素攻臀,淡藍(lán)色表示未排序,棗紅色柱表示當(dāng)前需排序元素纱昧,插入到橙色柱位置)
Matplotlib繪制動(dòng)態(tài)圖表的思路是將一系列圖按一定時(shí)間間隔順序播放刨啸,利用眼睛的視覺暫留形成動(dòng)態(tài)感,每張靜態(tài)圖就是一幀识脆。上面的代碼看上去有些長(zhǎng)设联,但大部分語(yǔ)句用來(lái)調(diào)顏色和標(biāo)簽文本,畫圖部分仍然是熟悉的fig,ax=plt.subplots()
建畫布灼捂、ax.bar()
畫柱狀圖离例、ax.set_title()
設(shè)置標(biāo)題、ax.annotate()
在每個(gè)柱的合適位置加文本標(biāo)簽悉稠。Matplotlib將動(dòng)圖相關(guān)的接口封裝在matplotlib.animation
里宫蛆,FuncAnimation(fig,func,frames)
通過重復(fù)調(diào)用func里的畫圖函數(shù)在fig上形成動(dòng)圖。FuncAnimation的參數(shù)如下:
fig
:用來(lái)生成動(dòng)畫的畫布的猛;func
:通過調(diào)用matplotlib繪圖方法來(lái)出圖作為動(dòng)圖的每一幀耀盗;frames
:一個(gè)迭代對(duì)象,會(huì)將其中每一個(gè)元素作為繪制一幀的參數(shù)傳入func函數(shù)卦尊;interval
:每一幀的展示時(shí)間叛拷,默認(rèn)200,單位是毫秒岂却,也就是200毫秒跳到下一張圖忿薇;
要將動(dòng)圖保存到文件通過.save(fname)
實(shí)現(xiàn),另外也可以用.to_html5_video()
把動(dòng)畫轉(zhuǎn)為HTML5下video標(biāo)簽支持的數(shù)據(jù)或用.to_jshtml
生成HTML表示的動(dòng)畫數(shù)據(jù)淌友,例如在jupyter notebook環(huán)境中煌恢,可以用以下語(yǔ)句直接渲染出帶播放控制臺(tái)的動(dòng)圖骇陈。
動(dòng)態(tài)排序圖實(shí)踐
學(xué)動(dòng)態(tài)圖繪制不應(yīng)該錯(cuò)過一直挺熱門的動(dòng)態(tài)排序圖(Bar Chart Race)震庭。通過一系列的條形圖營(yíng)造出你追我趕的熱鬧場(chǎng)面,看盡事件的變遷你雌。特別適合的應(yīng)用場(chǎng)景是各種排名的變化器联,如城市排名變化二汛、某些主題搜索指數(shù)變化、××沉浮史等拨拓。把這類圖拆解一下看到的是一系列條形圖和條柱之間的交換動(dòng)態(tài)效果肴颊。有了上面的插入排序做熱身,同樣可以通過繪制一系列條形圖再調(diào)用FuncAnimation(fig,func,frames)
得到動(dòng)態(tài)排序圖渣磷。網(wǎng)上可以找到各種年度季度排名的公開數(shù)據(jù)集婿着,一些講動(dòng)態(tài)排序圖的教程也給出了數(shù)據(jù)集。為了再降低數(shù)據(jù)獲取門檻醋界,我們直接隨機(jī)生成簡(jiǎn)單的排名數(shù)據(jù)竟宋。
假設(shè)我們有如下的數(shù)據(jù)表df,表示7位用戶A~G各自在3月到12月的消費(fèi)金額⌒畏模現(xiàn)在要畫出從3月到12月用戶消費(fèi)金額的排名變化丘侠。color列用來(lái)給各自標(biāo)識(shí)顏色,畫條形圖和畫制作動(dòng)圖所用接口和參數(shù)前面都講過(包括上篇文章)逐样,直接用ax.barh(y,width,color)
和FuncAnimation(fig,func,frames)
來(lái)繪制蜗字,條形圖是從下往上畫的,因此正序排序后正好是最高的柱在最上面脂新,不需要額外調(diào)轉(zhuǎn)挪捕,具體代碼如下。
fig,ax=plt.subplots()
def race_bar(i):
idx=str(i)
wdf=df.sort_values(by=idx)
width=list(wdf[idx])
yw=list(wdf['tag'])
ax.clear()
rs=ax.barh(yw,width,color=wdf['color'])
ax.set_xlim(0,wdf[idx].max()+200)
ax.set_title('A to G Animation')
ax.text(wdf[idx].max()+20,1,'{0}'.format(i),fontsize=30) #繪制當(dāng)前條形圖對(duì)應(yīng)時(shí)間周期
ax.tick_params(top=True, bottom=False,
labeltop=True, labelbottom=False)
c=0
for r in rs:
ax.annotate('{0}'.format(yw[c]),xy=(r.get_width()-40,r.get_y()+r.get_height()/2-0.16))
ax.annotate('{0}'.format(width[c]),xy=(r.get_width()+5,r.get_y()+r.get_height()/2-0.16))
c+=1
amt=anm.FuncAnimation(fig,race_bar,frames=range(3,13),interval=600)
#整體結(jié)構(gòu)和插入排序一脈相承
繪制效果如圖:
注:為了更好地獲得具有你追我趕争便、一同向前的效果担神,且防止數(shù)據(jù)變化太過跳脫,防止出現(xiàn)前一秒還是第一始花、突然掉到最后一名的劇烈變動(dòng)情況妄讯,生成df時(shí),不是全部使用隨機(jī)函數(shù)生成隨機(jī)數(shù)酷宵,此處使用的方法是第一次隨機(jī)生成數(shù)據(jù)亥贸,下一幀的數(shù)據(jù)在當(dāng)前數(shù)據(jù)基礎(chǔ)上加[-50,100]的值,本處設(shè)定是當(dāng)前數(shù)x[i]是偶數(shù)時(shí)浇垦,x[i+1]=x[i]+randint(20,200)炕置,奇數(shù)時(shí)x[i+1]=x+randint(-30,100)。生成數(shù)據(jù)集的代碼如下:
df=pd.DataFrame({'tag':list('ABCDEFG'),'color':['#1EAFAE', '#A3FFFF', '#69FFFF', '#BA5C25', '#FFA069', '#9E5B3A', '#D7CE88']})
df['3']=df['tag'].apply(lambda x:random.randint(50,600)) #初始列
for i in range(4,13):
idx=str(i-1) #偶數(shù)增幅男韧,奇數(shù)在原來(lái)基礎(chǔ)上[-30,50+5*i]變動(dòng)
df['{0}'.format(i)]=df[idx].apply(lambda x:x+random.randint(20,100+i*6) if x%2==0 else x+random.randint(-30,50+i*5))
動(dòng)態(tài)折線圖
換一種圖表類型也不難朴摊。最近動(dòng)態(tài)折線圖也很火。因?yàn)閐f也具有時(shí)間屬性此虑,這次只用A甚纲、B、C三行的數(shù)據(jù)繪制動(dòng)態(tài)折線圖朦前,改一下數(shù)據(jù)處理并將ax.bar()
換成ax.plot
介杆,成果如圖鹃操。
繪制代碼如下:
fig,ax=plt.subplots()
def race_line(i):
k=['A','B','C'] #只取3個(gè)人的數(shù)據(jù)
x=range(3,i+1)
ax.clear()
for ki in k:
wdf=df.loc[df['tag']==ki]
#篩選出畫折線的x,y
y=[list(wdf.loc[wdf['tag']==ki][str(j)])[0] for j in x]
ax.plot(x,y,color=list(wdf['color'])[0])
ax.text(i+0.2,y[-1]+2,'{0}:{1}'.format(ki,y[-1]))
ax.set_xlim(3,i+3)
ax.set_title('ABC Lines Animation')
ax.tick_params(top=True, bottom=False,left=False,right=True,
labelright=True,labelleft=False,
labeltop=True, labelbottom=False)
amt=anm.FuncAnimation(fig,race_line,frames=range(6,13),interval=500)
amt.save('lines-animation-1.gif') #把動(dòng)圖保存為gif文件
繪制三維動(dòng)態(tài)圖也是同樣的套路春哨,建畫布時(shí)加上projection="3d"
參數(shù)荆隘,繪圖時(shí)參數(shù)從[x,y]變成[x,y,z],其他按框架來(lái)做赴背。
形狀繪制深入
在上篇的圖表元素調(diào)校部分簡(jiǎn)單提到了在畫布上加橢圓椰拒、矩形的代碼,這里再細(xì)化一下Matplotlib可以繪制的形狀凰荚。整理如下:
#繪制基本形狀的框架耸三,以圓形為例
import matplotlib.patches as mpatches
from matplotlib.collections import PatchCollection
fig, ax = plt.subplots(subplot_kw=dict(aspect="equal")) #設(shè)置橫縱坐標(biāo)單位長(zhǎng)度一致,也可寫 plt.axis('equal')
patches = [] #需渲染的形狀集合
circle = mpatches.Circle((50,50),20) #初始化一個(gè)圓心在(50,50)浇揩,半徑為20的圓形
patches.append(circle)
pcc= PatchCollection(patches,color="#69FFFF") #因patches整合到了PatchCollection對(duì)象里,在Circle里寫顏色參數(shù)好像沒用仪壮,需要把color傳到這里
ax.add_collection(pcc)
ax.set_ylim(0,100) #設(shè)置x,y的展示范圍
ax.set_xlim(0,100)
.Circle(xy,radius,**kwargs)
: 繪制一個(gè)圓形胳徽,第一個(gè)參數(shù)是圓心坐標(biāo)积锅,可以傳數(shù)組或元組,x养盗、y不是單獨(dú)傳的缚陷;radius是圓的半徑;后續(xù)的參數(shù)有圖形標(biāo)簽(label)往核、線風(fēng)格(linestyle)箫爷、圓邊框?qū)挾?linewidth)、圖層順序(zorder)等聂儒;.Ellipse(xy,width,height,angle,**kwargs)
: 以xy為圓心繪制一個(gè)橢圓虎锚。Circle()的第二個(gè)參數(shù)是半徑,橢圓需要長(zhǎng)軸長(zhǎng)度和短軸長(zhǎng)度衩婚,也就是width和height窜护,angle控制旋轉(zhuǎn)角度,逆時(shí)針非春,按度計(jì)算柱徙,例如angle=90時(shí),原來(lái)一個(gè)扁的橢圓就變成了長(zhǎng)的橢圓奇昙,轉(zhuǎn)了90度护侮;其他參數(shù)和Circle()基本一致,下面也不再重復(fù)储耐。.Wedge(center, r, theta1, theta2, width, **kwargs)
: 楔形羊初,像劈掉一部分的圓,是餅圖的那一塊塊餅弧岳,可以猜測(cè)用pie()
繪制餅圖時(shí)調(diào)用了Wedge凳忙;center對(duì)應(yīng)圓的xy业踏,即圓心坐標(biāo)禽炬;r是半徑涧卵,只繪制從theta1到theta2之間的圓形,交換t1和t2可以得到餅的另一個(gè)部分腹尖,width默認(rèn)是None柳恐,當(dāng)設(shè)置了width會(huì)從r-width的部分開始畫,得到環(huán)狀圖热幔;.Rectangle(xy,width,height,angle=,**kwargs)
: 和橢圓的參數(shù)寫法驚人一致乐设,不同之處在于矩形的xy是左下角坐標(biāo)而不是中心的坐標(biāo);.RegularPolygon(xy,numVertices,radius,orientation,**kwargs)
: 繪制正多邊形xy是圖形的中心點(diǎn)绎巨,numVertices是頂點(diǎn)個(gè)數(shù)近尚,如numVertices=5是正五邊形;radius:從圖形中心xy到頂點(diǎn)的距離场勤;orientation:旋轉(zhuǎn)的度數(shù)戈锻,是弧度制;.Arrow(x,y,dx,dy, width, **kwargs)
: 繪制一個(gè)箭頭和媳,x:箭頭尾部的x坐標(biāo)格遭,y:箭頭尾部的y坐標(biāo);dx:箭頭指向位置距離x的長(zhǎng)度留瞳,dy同理拒迅,width是箭頭的寬度,默認(rèn)值是1她倘,當(dāng)形狀用一般設(shè)置得大一些璧微。另外還有hatch參數(shù)可以設(shè)置箭頭的底紋效果;.PathPatch(path, **kwargs)
: 繪制一系列坐標(biāo)構(gòu)成的路徑硬梁,是非常強(qiáng)大的接口往毡,繪制各種不規(guī)則的形狀、圖標(biāo)靶溜、貝塞爾曲線等一般都直接用Path的接口开瞭,和Canvas本身path對(duì)象的規(guī)則基本一致,東西比較多罩息,不好展開嗤详;.FancyBboxPatch(xy,width,boxstyle='round',**kwargs)
: 邊框效果更個(gè)性化的圖形,前面3個(gè)參數(shù)就是矩形的參數(shù)瓷炮,boxstyle控制繪制各種效果葱色,boxstyle支持的有circle(圓邊)、round(邊緣鈍化的矩形)娘香、square(方邊)苍狰、sawtooth(鋸齒邊)等办龄。下面的整理更形象。
基于上面的形狀淋昭,這里復(fù)現(xiàn)一下繪制經(jīng)典的數(shù)據(jù)科學(xué)維恩圖俐填。
畫維恩圖只需要Circle(xy,r)
就夠了,因patches整合到了PatchCollection對(duì)象里翔忽,在Circle里寫顏色參數(shù)似乎沒用英融,就把color從PatchCollection傳入。
#繪制基本形狀的框架歇式,以圓形為例
import matplotlib.patches as mpatches
from matplotlib.collections import PatchCollection
fig, ax = plt.subplots(subplot_kw=dict(aspect="equal")) #設(shè)置橫縱坐標(biāo)單位長(zhǎng)度一致驶悟,也可寫 plt.axis('equal')
patches = [] #需渲染的形狀集合
circle = mpatches.Circle((50,50),20) #初始化一個(gè)圓心在(50,50),半徑為20的圓形
patches.append(circle)
pcc= PatchCollection(patches,color="#69FFFF") #因patches整合到了PatchCollection對(duì)象里,在Circle里寫顏色參數(shù)好像沒用材失,需要把color傳到這里
ax.add_collection(pcc)
ax.set_ylim(0,100) #設(shè)置x痕鳍,y的展示范圍
ax.set_xlim(0,100)
另外一種畫多個(gè)圓的方法是用ax.add_artist(ada)
,示例代碼如下:
from mpl_toolkits.axes_grid1.anchored_artists import AnchoredDrawingArea
p1 = mpatches.Circle((15, 85), 78,fc='#1EAFAE',alpha=0.62) #(x,y),r,fcolor,alpha
ada = AnchoredDrawingArea(100,100,0, 0,loc=10, pad=0., frameon=False) #width( in pixels), height, xdescent, ydescent, loc, pad=0.4,
ada.drawing_area.add_artist(p1)
ax.add_artist(ada)
在matplotlib.image
的接口中有圖像的讀取接口龙巨,ax.imshow(mpimg.imread('imagename.png'))
可以讀取圖片并顯示笼呆,因此Matplotlib即能畫餅柱折點(diǎn)等圖形,也能畫更底層的線段恭应、楔形抄邀、多邊形,還能讀取圖片進(jìn)行處理昼榛。常用需求有給圖片加文本水印境肾、給圖形加圖片(如畫各國(guó)動(dòng)態(tài)排序柱圖時(shí)給對(duì)應(yīng)柱畫上國(guó)旗)、用形狀裁剪圖片等胆屿;
極坐標(biāo)
plt.subplot()
其中有一個(gè)參數(shù)是projection奥喻,表示所使用的坐標(biāo)系統(tǒng),之前畫三維圖的時(shí)候用到projection='3d'
非迹,畫心臟線函數(shù)的時(shí)候用到了projection='polar'
环鲤,再來(lái)細(xì)化一下極坐標(biāo)下的繪圖。
#極坐標(biāo)系下的可視化和直角坐標(biāo)沒多少改變
ax=plt.subplot(111,projection='polar')
x=[5,4,3,2,1]
ax.plot(x)
pyplot.subplot
支持的坐標(biāo)系統(tǒng)有'rectilinear'憎兽、'polar'冷离、'lambert'、'hammer'纯命、 'mollweide'西剥、'aitoff'等 看有哪些坐標(biāo)系統(tǒng),主要在3d繪圖亿汞、極坐標(biāo)繪圖瞭空、地圖投影等場(chǎng)景下使用。正如rectilinear直角坐標(biāo)系下確定一個(gè)位置用[x,y],在極坐標(biāo)系下定位一個(gè)位置通過[theta,r]咆畏,theta表示正方向旋轉(zhuǎn)的弧度南捂,r表示距離原點(diǎn)的直線距離(也稱r軸為極徑)。
極坐標(biāo)系可視化有一些基本的屬性可以設(shè)置旧找。
ax.set_theta_direction(-1)
: 設(shè)置極坐標(biāo)角度的正方向溺健,默認(rèn)值是1,表示逆時(shí)針方向钦讳,設(shè)置為-1時(shí)是順時(shí)針方向矿瘦;ax.set_theta_zero_location(loc,offset=0)
: 設(shè)置極坐標(biāo)洗0°的位置枕面,默認(rèn)是loc是'E'愿卒,表示正東方向,loc有八種選擇:("N", "NW", "W", "SW", "S", "SE", "E", "NE")潮秘,offset表示在loc的基礎(chǔ)上按照正方形偏移多少度數(shù)琼开;ax.set_thetagrids(angles,labels,fmt)
:設(shè)置極坐標(biāo)角度網(wǎng)格線上標(biāo)簽的顯示,labels是要顯示的標(biāo)簽枕荞,angles是標(biāo)簽所在對(duì)應(yīng)的角度(注意不是弧度)柜候,angles值的范圍應(yīng)該取[0,360], 默認(rèn)顯示0°躏精、45°渣刷、90°、135°矗烛、180°辅柴、225°、270°瞭吃、315°的網(wǎng)格線碌嘀。類似于直角坐標(biāo)系下的ax.set_xticklabels(df['x'])
;ax.set_rgrids(radii,labels)
: 設(shè)置極徑網(wǎng)格線和標(biāo)簽顯示歪架,和上面ax.set_thetagrids
效果對(duì)應(yīng)股冗;ax.set_rlabel_position(value)
: 設(shè)置極徑標(biāo)簽顯示位置,value為標(biāo)簽所要顯示在的角度和蚪;ax.set_rlim(0,30)
: 設(shè)置極徑顯示范圍止状,對(duì)應(yīng)直角坐標(biāo)下的set_ylim(0,30)
;ax.set_rscale()
: 設(shè)置極徑方向所用的比例尺攒霹,默認(rèn)是'linear'表示是線性變化怯疤,可以設(shè)置為'log'得到對(duì)數(shù)比例尺;
很多我們常見的圖將其轉(zhuǎn)到極坐標(biāo)系下會(huì)有驚艷的效果剔蹋,例如餅圖可以認(rèn)為是極坐標(biāo)系下的柱狀圖旅薄,將柱的高度映射為楔形的弧度;玫瑰圖可以是極坐標(biāo)系下的堆積柱狀圖,柱的高度映射為r及弧度theta的占比少梁;雷達(dá)圖可以是極坐標(biāo)系下的折線圖洛口。
我們用極坐標(biāo)繪制南丁格爾玫瑰圖的時(shí)候,可以再次復(fù)習(xí)柱狀圖bar的參數(shù)凯沪,代碼如下第焰。
y=[42, 142, 61, 119, 68]
z=[77, 46, 65, 81, 50]
ax=plt.subplot(111, projection='polar')
#對(duì)y和z進(jìn)行一些運(yùn)算以適應(yīng)弧度制
yw=[i*2*3.1416/sum(y) for i in y]
xw=[sum(y[0:i])*2*3.1416/sum(y) for i in range(len(y))]
yzw=[i*2*3.1416/sum(z) for i in z]
zw=[sum(z[0:i])*2*3.1416/sum(z) for i in range(len(z))]
ax.bar(xw,y,width=yw,align='edge',linewidth=1,edgecolor='k') #設(shè)置x對(duì)應(yīng)柱的邊緣開始畫而不是中心了
ax.bar(xw,y,width=yw,bottom=y,align='edge',linewidth=1,edgecolor='k') #設(shè)置柱的邊緣顏色以區(qū)分各個(gè)餅
轉(zhuǎn)換的過程需要對(duì)數(shù)據(jù)進(jìn)行換算,這算一個(gè)Matplotlib不夠智能的設(shè)置妨马,不能直接通過換坐標(biāo)系統(tǒng)的語(yǔ)句實(shí)現(xiàn)數(shù)據(jù)的一個(gè)換算挺举,例如將原先的x軸自動(dòng)換算到[0,2pi]繪制美觀的圖表,針對(duì)這種換坐標(biāo)系實(shí)現(xiàn)堆積的方法烘跺,基于屬性映射的可視化語(yǔ)法湘纵,會(huì)將換算細(xì)節(jié)封裝好,能直接使用出圖滤淳。
Matplotlib簡(jiǎn)單交互
Matplotlib畫靜態(tài)圖非常專業(yè)梧喷,同時(shí)它也能通過事件監(jiān)聽實(shí)現(xiàn)基礎(chǔ)的交互功能。Matplotlib通過plt.connect(s, func)
實(shí)現(xiàn)對(duì)鼠標(biāo)和鍵盤等事件的監(jiān)聽脖咐,s表示plt會(huì)關(guān)聯(lián)的事件铺敌,如s='button_press_event'表示按下鼠標(biāo)時(shí)會(huì)出發(fā)func函數(shù),在func里寫入觸發(fā)事件后的處理邏輯屁擅,相應(yīng)事件還有:{'key_press_event':'按下按鍵','key_release_event':'松開按鍵','resize_event':'改變窗體大小','close_event':'關(guān)閉窗體'}等偿凭。官網(wǎng)給了兩個(gè)例子分別表示按下按鈕時(shí)print相應(yīng)的坐標(biāo)以及按鍵時(shí)觸發(fā)保存圖片等交互∨筛瑁基于Matplotlib的接口要實(shí)現(xiàn)流暢復(fù)雜的交互代碼會(huì)很復(fù)雜弯囊。
自己簡(jiǎn)單實(shí)現(xiàn)了一下當(dāng)鼠標(biāo)點(diǎn)擊到柱狀圖的柱子上時(shí)會(huì)高亮當(dāng)前柱并顯示當(dāng)前柱對(duì)應(yīng)的值。效果如下:
具體代碼如下硝皂,jupyter notebook環(huán)境似乎不支持Matplotlib的交互操作常挚,需依賴GUI環(huán)境,因此運(yùn)行結(jié)果是通過腳本運(yùn)行得到的稽物。
from matplotlib.backend_bases import MouseButton
import matplotlib.pyplot as plt
xw=list('ABCDE')
yw=[42, 142, 61, 119, 68]
fig, ax = plt.subplots()
rs=ax.bar(xw,yw,color='#1EAFAE') #繪制初始的條形圖
ax.set_title('plt.connect demo')
def on_click_bar(event):
if event.button is MouseButton.LEFT:
x, y = event.xdata, event.ydata
print('w',x,y)
for r in range(len(rs)):
if x>rs[r].get_x() and x<rs[r].get_x()+rs[r].get_width() and y<rs[r].get_height():
print('q',x,y)
ax.clear()
c=['#BA5C25' if i==r else '#1EAFAE' for i in range(len(rs))]
ax.bar(xw,yw,color=c)
ax.text(x,y,'{0}'.format(rs[r].get_height()))
ax.set_title('plt.connect demo')
fig.canvas.draw_idle() #刷新當(dāng)前畫布
plt.connect('button_press_event', on_click_bar) #監(jiān)聽
plt.show()
關(guān)于Matplotlib庫(kù)奄毡,還可以深入的有:
圖形的布爾運(yùn)算、Path的具體規(guī)則等贝或;
漸變的顏色調(diào)節(jié)吼过;
地圖投影及basemap的使用;
根據(jù)三維數(shù)據(jù)繪制等高線
ax.contour(X, Y, Z,levels)
咪奖;
Matplotlib的各模塊內(nèi)容細(xì)化拆解會(huì)有非常多的內(nèi)容盗忱,市面上有挺多專門講mat可視化的厚書,如果只考慮快速使用和了解幾大模塊的話羊赵,Matplotlib的精要內(nèi)容是可以15分鐘學(xué)會(huì)的趟佃,個(gè)人認(rèn)為在知道了基本可視化框架后扇谣,了解折線圖。柱狀圖闲昭、餅圖罐寨、直方圖等的繪制方法和基本參數(shù),再學(xué)會(huì)添加文本序矩、調(diào)節(jié)坐標(biāo)軸鸯绿,會(huì)通過雙坐標(biāo)軸和子圖畫多張圖(上篇的內(nèi)容),最后了解下動(dòng)態(tài)圖和事件監(jiān)聽做基礎(chǔ)交互(本篇)簸淀。其他內(nèi)容和細(xì)節(jié)通過需求驅(qū)動(dòng)深入學(xué)瓶蝴。
參考資料
劉新宇.算法新解[M].人民郵電出版社,2017:19.