可視化技能之Matplotlib(下)|可視化系列02

在本系列的上篇文章里,我們從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
每次抓牌時(shí)判斷新牌的合適位置

為了直觀展示插入排序的關(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)圖骇陈。

jupyter上的動(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ù)的一種數(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)和插入排序一脈相承

繪制效果如圖:

Matplotlib繪制動(dòng)態(tài)排序圖

:為了更好地獲得具有你追我趕争便、一同向前的效果担神,且防止數(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介杆,成果如圖鹃操。

Matplotlib繪制動(dòng)態(tài)折線圖

繪制代碼如下:

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(鋸齒邊)等办龄。下面的整理更形象。

常用繪制形狀及參數(shù)

基于上面的形狀淋昭,這里復(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)
數(shù)據(jù)科經(jīng)典維恩圖

另外一種畫多個(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)與極坐標(biāo)對(duì)比

極坐標(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)變換

我們用極坐標(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)的值。效果如下:

柱狀圖對(duì)響應(yīng)點(diǎn)擊交互

具體代碼如下硝皂,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é)瓶蝴。

參考資料

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市租幕,隨后出現(xiàn)的幾起案子舷手,更是在濱河造成了極大的恐慌,老刑警劉巖令蛉,帶你破解...
    沈念sama閱讀 216,496評(píng)論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件聚霜,死亡現(xiàn)場(chǎng)離奇詭異狡恬,居然都是意外死亡珠叔,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,407評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門弟劲,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)祷安,“玉大人,你說我怎么就攤上這事兔乞』惚蓿” “怎么了?”我有些...
    開封第一講書人閱讀 162,632評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵庸追,是天一觀的道長(zhǎng)霍骄。 經(jīng)常有香客問我,道長(zhǎng)淡溯,這世上最難降的妖魔是什么读整? 我笑而不...
    開封第一講書人閱讀 58,180評(píng)論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮咱娶,結(jié)果婚禮上米间,老公的妹妹穿的比我還像新娘。我一直安慰自己膘侮,他們只是感情好屈糊,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,198評(píng)論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著琼了,像睡著了一般逻锐。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,165評(píng)論 1 299
  • 那天昧诱,我揣著相機(jī)與錄音慷丽,去河邊找鬼。 笑死鳄哭,一個(gè)胖子當(dāng)著我的面吹牛要糊,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播妆丘,決...
    沈念sama閱讀 40,052評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼锄俄,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了勺拣?” 一聲冷哼從身側(cè)響起奶赠,我...
    開封第一講書人閱讀 38,910評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎药有,沒想到半個(gè)月后毅戈,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,324評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡愤惰,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,542評(píng)論 2 332
  • 正文 我和宋清朗相戀三年苇经,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片宦言。...
    茶點(diǎn)故事閱讀 39,711評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡扇单,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出奠旺,到底是詐尸還是另有隱情购裙,我是刑警寧澤旱爆,帶...
    沈念sama閱讀 35,424評(píng)論 5 343
  • 正文 年R本政府宣布某残,位于F島的核電站译荞,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏忿晕。R本人自食惡果不足惜装诡,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,017評(píng)論 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望杏糙。 院中可真熱鬧慎王,春花似錦、人聲如沸宏侍。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,668評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)谅河。三九已至咱旱,卻和暖如春确丢,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背吐限。 一陣腳步聲響...
    開封第一講書人閱讀 32,823評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工鲜侥, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人诸典。 一個(gè)月前我還...
    沈念sama閱讀 47,722評(píng)論 2 368
  • 正文 我出身青樓描函,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親狐粱。 傳聞我的和親對(duì)象是個(gè)殘疾皇子舀寓,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,611評(píng)論 2 353

推薦閱讀更多精彩內(nèi)容