前幾天在網(wǎng)上看到有人用 matplotlib 繪制了漫威里幾大英雄的戰(zhàn)斗力圖,趕腳灰常有意思。作為漫威和 python 的雙重粉絲,我這次又 hold 不住了,于是也做了一個 pyecharts 版的實(shí)力對比圖,在這里分享給大家。
這次我繪制的這個圖和網(wǎng)上 matplotlib 版本的圖有以下區(qū)別:1. 加入了交互功能,可以查看任意一個英雄的數(shù)值,真正做到“想點(diǎn)哪里點(diǎn)哪里”(媽媽再也不用擔(dān)心我的學(xué)習(xí)了)2. 將多個英雄的圖放在一個圖表里,方便對比,同時也可以單獨(dú)查看某個英雄數(shù)值3. 加入了圖片背景,體現(xiàn)作為漫威粉絲的B格
首先還是導(dǎo)入各種功能模塊。opts(options)是 pyecharts 中設(shè)置圖片詳細(xì)格式的模塊,Radar 是繪制雷達(dá)圖的類名,因?yàn)槔L制超級英雄的戰(zhàn)斗力(包含多個數(shù)值),用雷達(dá)圖比較適合,JsCode 是 pyecharts 中執(zhí)行 JavaScript 代碼的一個類。from pyecharts import options as optsfrom pyecharts.charts import Radarfrom pyecharts.commons.utils import JsCode
接下來是設(shè)置各個超級英雄的戰(zhàn)斗力數(shù)值,這次的戰(zhàn)斗力數(shù)值來自于百度百科:https://baike.baidu.com/item/%E6%BC%AB%E5%A8%81%E4%BA%BA%E7%89%A9%E8%83%BD%E5%8A%9B%E6%95%B0%E5%80%BC/17935032我們選取復(fù)聯(lián)六巨頭的戰(zhàn)斗力數(shù)值(美國隊(duì)長、鋼鐵俠、黑寡婦、鷹眼、綠巨人以及雷神),數(shù)值內(nèi)容并不多,主要代碼如下所示:captain_america = [{"value": [4, 4, 4, 4, 1, 7], "name": "美國隊(duì)長"}]iron_man= [{"value": [6, 3, 5, 3, 5, 3], "name": "鋼鐵俠"}]black_widow = [{"value": [3, 3, 2, 3, 2, 7], "name": "黑寡婦"}]hawkeye = [{"value": [3, 3, 3, 2, 3, 7], "name": "鷹眼"}]hulk = [{"value": [2, 7, 3, 7, 1, 3], "name": "綠巨人"}]thor = [{"value": [2, 7, 6, 7, 7, 6], "name": "雷神"}]
這6個人的數(shù)值都用他們各自的英文名作變量名,每個變量是一個 list,里面包含一個 dict,dict 中 value 就代表了每個人的戰(zhàn)斗力數(shù)值,其同樣是一個 list,包含6個數(shù)據(jù):智力、力量、速度、耐力、能量發(fā)射和戰(zhàn)斗技能。后面的 name 則是每個人的中文名,實(shí)際上 name 在整個代碼中并沒有什么作用,只方便顯示。
接下來是一個名為 myschema 的變量,是一個 list,里面包含6個 dict,每個 dict 包含3個 key,這6個 dict 主要用來設(shè)置雷達(dá)圖的坐標(biāo)軸,后面會詳細(xì)說明。
myschema = [ {"name": '智力', "max": 7, "min": 0}, {"name": '力量', "max": 7, "min": 0}, {"name": '速度', "max": 7, "min": 0}, {"name": '耐力', "max": 7, "min": 0}, {"name": '能量發(fā)射', "max": 7, "min": 0}, {"name": '戰(zhàn)斗技能', "max": 7, "min": 0}]
然后就開始我們的主要繪圖部分。首先生成一個 Radar 類的實(shí)例 r,在這里我們設(shè)置了圖表的背景圖,用到的是 opts.InitOpts 中的 bg_color 屬性,其值為
{"type": "pattern", "image": JsCode("img"), "repeat": "no-repeat"}
"type": "pattern" 表示我們用圖片作背景,"image": JsCode("img") 表示我們用 JavaScript 代碼來設(shè)置這個背景圖,"repeat": "no-repeat" 表示圖片不重復(fù)。而 add_js_funcs 方法就是執(zhí)行相關(guān)的 JavaScript 代碼,這里的 JavaScript 代碼也很簡單,就設(shè)置一個名為 img 的變量,指定一下路徑。在這里我們用的圖片是本地圖片,名為 a5.png,我們要把這個圖片放在自己的當(dāng)前工作目錄下,不知道當(dāng)前工作目錄的可以執(zhí)行下面的代碼查看:import osroot = os.getcwd()print(root)
當(dāng)然這里我們也可以用網(wǎng)上的圖片,只要把 img.src 設(shè)置為圖片的網(wǎng)址就OK了。r = Radar(init_opts=opts.InitOpts( bg_color={"type": "pattern", "image": JsCode("img"), "repeat": "no-repeat"} )) #初始化雷達(dá)圖r.add_js_funcs( """ var img = new Image(); img.src = 'a5.png'; """) #執(zhí)行js代碼
接下來是一個長長的 chaining methods(方法鏈),雖然內(nèi)容多了點(diǎn),但不少都是重復(fù)性代碼,所以并不難理解,這里介紹一下里面的主要部分。
add_schema 方法就是設(shè)置我們的雷達(dá)圖,參數(shù) schema 設(shè)置為 myschema,就是前面我們提到過的那個 list,里面有6個 dict,每個 dict 就是一個徑向軸,dict 的 name 就是徑向軸的標(biāo)簽,min 和 max 設(shè)置徑向軸的最小和最大值。shape 是雷達(dá)圖的形狀,這里設(shè)置為圓形,也可以設(shè)置為多邊形 polygon。center=["50%", "50%"] 表示雷達(dá)圖的中心在當(dāng)前繪圖區(qū)域的中點(diǎn)位置,即當(dāng)前繪圖區(qū)域的高度和寬度的50%位置,radius="80%" 表示雷達(dá)圖的半徑為當(dāng)前繪圖區(qū)域的大小的80%,即這個區(qū)域的寬度和高度中的較小者的80%。angleaxis_opts 參數(shù)是用來設(shè)置角度坐標(biāo)軸,其2個參數(shù) axistick_opts、axislabel_opts 全都設(shè)為不顯示,他們的分別代表了角度軸的刻度、標(biāo)簽,大家可以試試把這些參數(shù)設(shè)置為 True 的結(jié)果。然后是參數(shù) radiusaxis_opts,其用來設(shè)置徑向軸,其最小值為0,最大值為7,間隔為1,其包含的 splitarea_opts 參數(shù)用來設(shè)置間隔區(qū)域,也就是圖中灰色的部分。而 polar_opts 參數(shù)則是設(shè)置這個雷達(dá)圖的相關(guān)屬性,這里我們?nèi)坎捎媚J(rèn)設(shè)置。而 add_schema 的另外兩個參數(shù) splitline_opt 和 textstyle_opts 則分別用來設(shè)置徑向軸的分割線和圖中文字,這里我們把分割線設(shè)為不顯示,文章顏色設(shè)為黑色。r 的 add 方法則用來向圖中添加數(shù)據(jù),每個 add 方法會添加一個數(shù)據(jù),因?yàn)槲覀円还灿?個超級英雄,所以用了6次 add 方法。add 方法中 series_name 用來設(shè)置數(shù)據(jù)序列的名稱,這也就是圖中上面一排圓圈后面的文字,data 是所要輸入的數(shù)據(jù),areastyle_opts 用來設(shè)置每個數(shù)據(jù)序列圖形區(qū)域的屬性,這里把每個圖形區(qū)域的不透明度設(shè)為0.1,linestyle_opts 設(shè)置圖形連線的屬性,這里把線寬設(shè)為1。set_global_opt 則用來設(shè)置整個圖表的屬性,這里我們設(shè)置圖的標(biāo)題為"復(fù)聯(lián)六巨頭實(shí)力對比"。最后我們用 render 生成一個網(wǎng)頁。( r.add_schema( #設(shè)置雷達(dá)圖的各種屬性 schema=myschema, shape="circle", center=["50%", "50%"], #圖片中心位置 radius="80%", #雷達(dá)圖半徑大小 angleaxis_opts=opts.AngleAxisOpts( axistick_opts=opts.AxisTickOpts(is_show=False), axislabel_opts=opts.LabelOpts(is_show=False), ), radiusaxis_opts=opts.RadiusAxisOpts( min_=0, max_=7, interval=1, splitarea_opts=opts.SplitAreaOpts( is_show=True, areastyle_opts=opts.AreaStyleOpts(opacity=1) ) ), polar_opts=opts.PolarOpts(), splitline_opt=opts.SplitLineOpts(is_show=False), textstyle_opts=opts.TextStyleOpts(color="black"), ) .add( series_name="美國隊(duì)長", data=captain_america, areastyle_opts=opts.AreaStyleOpts(opacity=0.1), linestyle_opts=opts.LineStyleOpts(width=1), ) .add( series_name="鋼鐵俠", data=iron_man, areastyle_opts=opts.AreaStyleOpts(opacity=0.1), linestyle_opts=opts.LineStyleOpts(width=1), ) .add( series_name="黑寡婦", data=black_widow, areastyle_opts=opts.AreaStyleOpts(opacity=0.1), linestyle_opts=opts.LineStyleOpts(width=1), ) .add( series_name="鷹眼", data=hawkeye, areastyle_opts=opts.AreaStyleOpts(opacity=0.1), linestyle_opts=opts.LineStyleOpts(width=1), ) .add( series_name="綠巨人", data=hulk, areastyle_opts=opts.AreaStyleOpts(opacity=0.1), linestyle_opts=opts.LineStyleOpts(width=1), ) .add( series_name="雷神", data=thor, areastyle_opts=opts.AreaStyleOpts(opacity=0.1), linestyle_opts=opts.LineStyleOpts(width=1), ) .set_global_opts( title_opts=opts.TitleOpts(title="復(fù)聯(lián)六巨頭實(shí)力對比") ) .render('ht1.html'))
生成的結(jié)果如圖2所示:
在我們繪制的圖中,如果想只查看某個英雄的數(shù)值,我們則可以單擊其他英雄的序列名稱,就是圖中上面那一排小圓圈和后面的文字,每次單擊就會使這個英雄的名稱變成灰色,其代表的圖形也會在圖中消失,再次單擊則會復(fù)原,這樣就會只留下我們需要的英雄的數(shù)值。如圖3所示,我們只留下綠巨人的圖。pyecharts 的優(yōu)點(diǎn)是繪圖快、交互設(shè)計好,它提供了很多 matplotlib 不具備或很難實(shí)現(xiàn)的功能,這給我們在繪制交互式圖表時提供了更好的選擇。本文所有圖片和代碼都已上傳,如有需要可自行下載:https://gitee.com/crossin/snippet/tree/master/marvel-radar小李子,數(shù)據(jù)分析愛好者,擅長數(shù)據(jù)可視化,比較關(guān)注機(jī)器學(xué)習(xí)領(lǐng)域,希望能和業(yè)內(nèi)朋友多學(xué)習(xí)交流,個人微信tyrant100。