有趣的圖形:用Python繪制帶餅圖的散點(diǎn)圖兼論marker的隱藏功能

01 帶餅圖的散點(diǎn)圖

有這樣一個(gè)例子:假設(shè)有五個(gè)人查描,每個(gè)人的月均收入水平為a=[1,3,2,4,3]扣蜻,消費(fèi)水平b=[2,1,3,3,5]走孽,數(shù)據(jù)單位均有千元钝的。同時(shí)五個(gè)人消費(fèi)水平中翁垂,按照每月衣食住行的消費(fèi)比例為:

s1=[0.1,0.2,0.3,0.4]

s2=[0.35,0.35,0.2,0.1]

s3=[0.2,0.25,0.25,0.3]

s4=[0.5,0.1,0.15,0.25]

s5=[0.0,0.25,0.4,0.35]

依據(jù)上述數(shù)據(jù)(數(shù)據(jù)純屬虛構(gòu)),我可以將這些數(shù)據(jù)畫(huà)在一個(gè)圖形里硝桩,如圖:
image.png

(其中沿猜,藍(lán)色:衣;黃色:食碗脊;紅色:滋浼纭;綠色:行)
這個(gè)圖形就是帶餅圖的散點(diǎn)圖衙伶,從圖中不僅可以看出五個(gè)人的消費(fèi)與收入的關(guān)系趨勢(shì)祈坠,也可以看出每個(gè)人的衣食住行消費(fèi)比例不同。
是不是很有趣的一個(gè)圖形矢劲?它是怎么做出來(lái)的赦拘?

02 matplotlib中marker參數(shù)的一個(gè)隱藏功能

上圖是用python中matplotlib包繪制的,而繪制成帶餅圖的散點(diǎn)圖則是用了里邊關(guān)鍵的marker參數(shù)卧须,所以在介紹如何繪制此圖之前另绩,先說(shuō)說(shuō)marker參數(shù)的一個(gè)隱藏功能儒陨。
一般的我們繪制散點(diǎn)圖基本的命令為:

import matplotlib.pyplot as plt
plt.scatter(x, y, s=20, c=None, marker='o')

其中,s是點(diǎn)的大小笋籽,c是顏色蹦漠,marker就是指定點(diǎn)標(biāo)記的形狀,在這里用的就是小圓點(diǎn)o车海;我們還可以用“*”笛园、“x”、“Δ”等等侍芝,甚至還有數(shù)字研铆、字母所代表的形狀。

事實(shí)上州叠,不僅僅如此棵红,在marker的help文檔中還指出了一個(gè)我們不經(jīng)常用的標(biāo)記方式,那就是元組——(numsides, style, angle)咧栗,numsides是邊的個(gè)數(shù)逆甜,angle是旋轉(zhuǎn)角度,style只有0,1,2,3四個(gè)值致板,舉個(gè)例子交煞。我設(shè)置marker=(9,0, 30),就出來(lái)個(gè)九邊形的散點(diǎn)圖斟或,如下:
image.png
這種定義方式大大拓展了散點(diǎn)形狀的自定義方式素征,本文所做的餅圖也源于此。

03 單個(gè)帶餅圖的散點(diǎn)圖繪制過(guò)程
但是萝挤,完全繪制成上述那個(gè)圖形也并非那么容易御毅,下面我們從一個(gè)帶餅圖的散點(diǎn)繪制講起。
比如上面的a=1平斩,b=2那個(gè)點(diǎn)的消費(fèi)比例為:s1=[0.1,0.2,0.3,0.4]亚享,代碼如下:

x = [0] + np.cos(np.linspace(0, 2 * np.pi * 0.1, 5)).tolist()#[0]表示x的初始值
y = [0] + np.sin(np.linspace(0, 2 * np.pi * 0.1, 5)).tolist() #用tolist()形成數(shù)列
xy1 = list(zip(x, y))

x = [0] + np.cos(np.linspace(2 * np.pi * 0.1, 2 * np.pi * 0.3, 5)).tolist()
y = [0] + np.sin(np.linspace(2 * np.pi * 0.1, 2 * np.pi * 0.3, 5)).tolist()
xy2 = list(zip(x, y))

x = [0] + np.cos(np.linspace(2 * np.pi * 0.3, 2 * np.pi* 0.6, 5)).tolist()
y = [0] + np.sin(np.linspace(2 * np.pi * 0.3, 2 * np.pi* 0.6, 5)).tolist()
xy3 = list(zip(x, y))

x = [0] + np.cos(np.linspace(2 * np.pi * 0.6, 2 * np.pi*1, 5)).tolist()
y = [0] + np.sin(np.linspace(2 * np.pi * 0.6, 2 * np.pi*1, 5)).tolist()
xy4 = list(zip(x, y))
fig, ax = plt.subplots()
ax.scatter(a[0], b[0], marker=(xy1),
            s=500,facecolor='blue')
ax.scatter(a[0], b[0], marker=(xy2),
           s=500,facecolor='y')
ax.scatter(a[0], b[0], marker=(xy3),
            s=500,facecolor='red')
ax.scatter(a[0], b[0], marker=(xy4),
            s=500,facecolor='green') #為了餅圖看得清,散點(diǎn)的size要大一些

plt.show()

得到結(jié)果就是:
image.png

首先講講x绘面、y變量的生成欺税,其原理是先根據(jù)每個(gè)占比數(shù)值所形成的角度(乘以2π,如2 * np.pi * 0.1)揭璃,然后再用np.linspace函數(shù)五等分形成6個(gè)角度值晚凿,每個(gè)值賦予cos、sin函數(shù)瘦馍,這是因?yàn)閏os2θ+sin2θ=1歼秽,所有經(jīng)過(guò)cos、sin函數(shù)的值會(huì)自動(dòng)形成一個(gè)圓形情组。
值得注意的是燥筷,因?yàn)樗膫€(gè)占比要圍成一個(gè)圓形箩祥,所以除了第一個(gè)占比外,后邊的都要用累計(jì)占比肆氓,如第二個(gè)0.2的占比np.linspace(2 * np.pi * 0.1, 2 * np.pi * 0.3, 5)袍祖,第三個(gè)0.3的就是0.3-0.6之間,第四個(gè)是0.6-1之間谢揪。
如果還沒(méi)明白那就單獨(dú)把一個(gè)x蕉陋、y生成的變量,單獨(dú)作圖可以看一下:

x = [0] + np.cos(np.linspace(0, 2 * np.pi * 0.1, 5)).tolist()
y = [0] + np.sin(np.linspace(0, 2 * np.pi * 0.1, 5)).tolist()
plt.plot(x,y,c='b')
plt.show()
image.png

可以看出拨扶,第一個(gè)占比x凳鬓、y的軌跡就是一個(gè)弧形,然后再用初始值(0患民,0)牽引著缩举,這樣再對(duì)這個(gè)軌跡進(jìn)行填充時(shí),就會(huì)形成一個(gè)扇形酒奶,如下:

plt.scatter(a[0], b[0], marker=(xy1),
            s=500,facecolor='blue')
plt.show()
image.png

這樣一個(gè)x蚁孔、y所形成的marker=(xy1)標(biāo)記,再用facecolor='blue'填充就會(huì)形成一個(gè)扇形散點(diǎn)標(biāo)記惋嚎。最后用fig, ax = plt.subplots()把xy2、xy3站刑、xy4所有子圖都放上去另伍,就形成一個(gè)圓形,然后用不同顏色填充绞旅,就形成一個(gè)餅圖摆尝,每個(gè)餅圖的角度大小由其占比比例決定。

04 所有點(diǎn)的餅圖-散點(diǎn)圖
上邊是一個(gè)點(diǎn)的餅圖-散點(diǎn)圖因悲,若是將a=[1,3,2,4,3]堕汞,b=[2,1,3,3,5],以及b的所有個(gè)體衣食住行的消費(fèi)比例全放進(jìn)去晃琳,那就需要用到while讯检、for循環(huán)條件,代碼如下:

#5個(gè)消費(fèi)水平下衣食住行的占比
s1=[0.1,0.2,0.3,0.4] 
s2=[0.35,0.35,0.2,0.1]
s3=[0.2,0.25,0.25,0.3]
s4=[0.5,0.1,0.15,0.25]
s5=[0.0,0.25,0.4,0.35]
#計(jì)算累計(jì)占比
ss1=[s1[0],sum(s1[0:2]),sum(s1[0:3]),sum(s1[0:4])] 
ss2=[s2[0],sum(s2[0:2]),sum(s2[0:3]),sum(s2[0:4])]
ss3=[s3[0],sum(s3[0:2]),sum(s3[0:3]),sum(s3[0:4])]
ss4=[s4[0],sum(s4[0:2]),sum(s4[0:3]),sum(s4[0:4])]
ss5=[s5[0],sum(s5[0:2]),sum(s5[0:3]),sum(s5[0:4])]

s=[ss1,ss2,ss3,ss4,ss5]
a=[1,3,2,4,3] #收入水平(千元)
b=[2,1,3,3,5] #消費(fèi)水平(千元)
fig, ax = plt.subplots(figsize=(10,6))
i=0
while i<len(b):
    x = [0] + np.cos(np.linspace(0, 2 * np.pi * s[i][0], 15)).tolist()
    y = [0] + np.sin(np.linspace(0, 2 * np.pi * s[i][0], 15)).tolist()
    xy1 = list(zip(x, y))

    x = [0] + np.cos(np.linspace(2 * np.pi * s[i][0], 2 * np.pi * s[i][1], 15)).tolist()
    y = [0] + np.sin(np.linspace(2 * np.pi * s[i][0], 2 * np.pi * s[i][1], 15)).tolist()
    xy2 = list(zip(x, y))

    x = [0] + np.cos(np.linspace(2 * np.pi * s[i][1], 
                                 2 * np.pi* s[i][2], 15)).tolist()
    y = [0] + np.sin(np.linspace(2 * np.pi * s[i][1], 
                                 2 * np.pi* s[i][2],  15)).tolist()
    xy3 = list(zip(x, y))

    x = [0] + np.cos(np.linspace(2 * np.pi * s[i][2], 
                                 2 * np.pi*1, 15)).tolist()
    y = [0] + np.sin(np.linspace(2 * np.pi * s[i][2], 
                                 2 * np.pi*1, 15)).tolist()
    xy4 = list(zip(x, y))
    xy=[xy1,xy2,xy3,xy4]
    c=['b','y','r','g']
    for j in range(4):
        ax.scatter(a[i], b[i], marker=(xy[j]),
                s=800,facecolor=c[j])
        
    i=i+1

plt.show()

最終得到本文前邊那個(gè)圖形卫旱。
另外還需說(shuō)明一下人灼,這個(gè)圖形只適用于小樣本數(shù)據(jù),也就是圖形三點(diǎn)的個(gè)數(shù)不能太多顾翼,每個(gè)點(diǎn)中比例數(shù)量也不能太多投放,否則影響展示效果。

寫(xiě)作不易适贸,特別是技術(shù)類的寫(xiě)作灸芳,請(qǐng)大家多多支持涝桅,關(guān)注、點(diǎn)贊烙样、轉(zhuǎn)發(fā)等等苹支,也歡迎大家關(guān)注知乎爬蟲(chóng)與數(shù)據(jù)分析專欄:https://zhuanlan.zhihu.com/zjying2000

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末误阻,一起剝皮案震驚了整個(gè)濱河市债蜜,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌究反,老刑警劉巖寻定,帶你破解...
    沈念sama閱讀 222,252評(píng)論 6 516
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異精耐,居然都是意外死亡狼速,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,886評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門卦停,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)向胡,“玉大人,你說(shuō)我怎么就攤上這事惊完〗┣郏” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 168,814評(píng)論 0 361
  • 文/不壞的土叔 我叫張陵小槐,是天一觀的道長(zhǎng)拇派。 經(jīng)常有香客問(wèn)我,道長(zhǎng)凿跳,這世上最難降的妖魔是什么件豌? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 59,869評(píng)論 1 299
  • 正文 為了忘掉前任,我火速辦了婚禮控嗜,結(jié)果婚禮上茧彤,老公的妹妹穿的比我還像新娘。我一直安慰自己疆栏,他們只是感情好曾掂,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,888評(píng)論 6 398
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著承边,像睡著了一般遭殉。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上博助,一...
    開(kāi)封第一講書(shū)人閱讀 52,475評(píng)論 1 312
  • 那天险污,我揣著相機(jī)與錄音,去河邊找鬼。 笑死蛔糯,一個(gè)胖子當(dāng)著我的面吹牛拯腮,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播蚁飒,決...
    沈念sama閱讀 41,010評(píng)論 3 422
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼动壤,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了淮逻?” 一聲冷哼從身側(cè)響起琼懊,我...
    開(kāi)封第一講書(shū)人閱讀 39,924評(píng)論 0 277
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎爬早,沒(méi)想到半個(gè)月后哼丈,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,469評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡筛严,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,552評(píng)論 3 342
  • 正文 我和宋清朗相戀三年醉旦,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片桨啃。...
    茶點(diǎn)故事閱讀 40,680評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡车胡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出照瘾,到底是詐尸還是另有隱情匈棘,我是刑警寧澤,帶...
    沈念sama閱讀 36,362評(píng)論 5 351
  • 正文 年R本政府宣布网杆,位于F島的核電站羹饰,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏碳却。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,037評(píng)論 3 335
  • 文/蒙蒙 一笑旺、第九天 我趴在偏房一處隱蔽的房頂上張望昼浦。 院中可真熱鬧,春花似錦筒主、人聲如沸关噪。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,519評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)使兔。三九已至,卻和暖如春藤韵,著一層夾襖步出監(jiān)牢的瞬間虐沥,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,621評(píng)論 1 274
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留欲险,地道東北人镐依。 一個(gè)月前我還...
    沈念sama閱讀 49,099評(píng)論 3 378
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像天试,于是被迫代替她去往敵國(guó)和親槐壳。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,691評(píng)論 2 361

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