勒布朗生涯資料視覺化(二)用Matplotlib製作柱形圖及Figure, Text類和bar函式的引數探索
簡介
- 本篇文章使用Kaggle.com上的資料集NBA Players stats since 1950中的Seasons_Stats.csv,其包含從1950至今的每個賽季的球員資料,每條資料有53項欄目,是綜合性較強的NBA資料集,我嘗試從中提取勒布朗詹姆斯的生涯資料,並用Matplotlib庫實現視覺化功能。
- 第二部分中我們使用第一部分檢索出來的相關資料,並繪製出定制樣式的柱形圖,效果如下:
配置
- 語言:Scala 2.11
- Spark版本:Spark 2.3.1
主要內容
- 建立Figure並分為多個子Plot,分別做圖
- Text類解析
- 條形圖Bar的建立及屬性設定
- 為條形圖設定影象上面的具體資料標記
- 條形圖座標軸的域及精度設定
- 通過Fontdict來設定字型樣式
程式設計實踐
讀取資料並轉換格式
第二部分我們獲取了勒布朗詹姆斯的九項資料,並儲存到csv檔案中:
2004,2005,2006,2007,2008,2009,2010,2011,2012,2013,2014,2015,2016,2017 20.937,27.188,31.367,27.333,30.0,28.444,29.711,26.722,27.145,26.789,27.13,25.261,25.263,26.405 5.468,7.35,7.038,6.744,7.893,7.568,7.289,7.468,7.935,8.026,6.922,6.029,7.434,8.649 5.886,7.212,6.595,6.026,7.187,7.247,8.566,7.013,6.242,7.25,6.338,7.406,6.763,8.73 1.646,2.212,1.557,1.603,1.84,1.691,1.645,1.57,1.855,1.697,1.571,1.58,1.368,1.243 0.734,0.65,0.835,0.705,1.08,1.148,1.013,0.633,0.806,0.882,0.338,0.71,0.645,0.595 79.0,80.0,79.0,78.0,75.0,81.0,76.0,79.0,62.0,76.0,77.0,69.0,76.0,74.0 0.417,0.472,0.48,0.476,0.484,0.489,0.503,0.51,0.531,0.565,0.567,0.488,0.52,0.548 0.29,0.351,0.335,0.319,0.315,0.344,0.333,0.33,0.362,0.406,0.379,0.354,0.309,0.363
這九項資料分別代表年份、得分、籃板、助攻、搶斷、籃板、出場數、投籃命中率和三分球命中率,下面我們將其讀到我們的Python檔案中:
lebron_info = open("D:/SparkProjects/NBADataBase/data/lebron_data.csv")
yearList = [int(i) for i in lebron_info.readline().split(',')]
pointsList = [float(i) for i in lebron_info.readline().split(',')]
reboundsList = [float(i) for i in lebron_info. readline().split(',')]
assistsList = [float(i) for i in lebron_info.readline().split(',')]
stealsList = [float(i) for i in lebron_info.readline().split(',')]
blocksList = [float(i) for i in lebron_info.readline().split(',')]
gamesList = [float(i) for i in lebron_info.readline().split(',')]
fieldPercentList = [float(i) for i in lebron_info.readline().split(',')]
threePercentList = [float(i) for i in lebron_info.readline().split(',')]
筆者原本想使用Python的自帶CSV檔案處理庫 CSV File Reading and Writing,可是由於筆者需要將檔案中內容儲存到不同的List中儲存,使用其更顯繁瑣,故使用了最笨的方法, 一行一行讀取檔案,用split函式轉換為List,並強制改變了不同List中的資料型別。
設定頁面主標題,並將其分割為多個子區域
如上所述,我們有九類資料,現考慮將年份作為橫座標,將其餘資料作為縱座標做表,考慮到不同型別資料的資料值域差別很大,繪製在同一個圖中十分難獲取相關資訊,故我們將其分為八個子區域分別作圖:
引數名 | 意義 |
---|---|
figsize | 尺寸大小,預設為介面大小 |
dpi | “Dots per inch”,衡量影象點密度的指數 |
facecolor | 規定介面的顏色 |
edgecolor | 介面邊緣的顏色 |
linewidth | 邊緣的寬度引數 |
frameon | 是否顯示邊框的引數 |
subplotpars | 子區域的相關引數 |
tight_layout | 可以通過包含“w_pad”、"h_pad"和"rect"的字典來改變邊緣引數 |
constrained_layout | 若設定為True則可以自動調整子區域和裝飾區域的 |
在此我們通過figsize來將影象大小設定得適中,再通過facecolor設定背景色,然後通過layout這一dict型別資料設定了pad的大小,即邊框區域的面積
layout = {
'pad': 5
}
fig = plt.figure(figsize=[26, 10], facecolor='#CD00CD', tight_layout=layout)
然後我們設定了主標題:
fig.suptitle("LeBron James's Statistics 2003-2018", fontstyle='italic',
fontweight='bold', fontsize=30, color='#FFD700',
horizontalalignment='center', verticalalignment='top')
在此我們通過subtitle裡面的Text屬性定製了字型樣式,我們順便來看一下Text類包含什麼引數,來自text - Matplotlib 3.0.0 documentation,我挑選了幾個最常用的引數來介紹:
引數名 | 介紹 |
---|---|
backgroundcolor | 背景顏色 |
color | 字型顏色 |
fontfamily | 設定的字型族名稱或/及類族名稱的一個優先表,會以第一個可以識別的字型為準進行設定,可選值 {FONTNAME, ‘serif’, ‘sans-serif’, ‘cursive’, ‘fantasy’, ‘monospace’} |
fontname | 選擇的字型名稱,若不存在則設定為預設字型可選值 {FONTNAME, ‘serif’, ‘sans-serif’, ‘cursive’, ‘fantasy’, ‘monospace’} |
fontsize | 字型大小,可以設定為標識字號的數字,或字串{ ‘xx-small’, ‘x-small’, ‘small’, ‘medium’, ‘large’, ‘x-large’, ‘xx-large’} |
fontstretch | 字型的壓縮屬性,可以是0-1000的一個數值,也可以是字串{‘ultra-condensed’, ‘extra-condensed’, ‘condensed’, ‘semi-condensed’, ‘normal’, ‘semi-expanded’, ‘expanded’, ‘extra-expanded’, ‘ultra-expanded’} |
fontstyle | 可規定字型的傾斜效果,可選 {‘normal’, ‘italic’, ‘oblique’},後兩個值均代表傾斜,區別是’italic’從字型自帶的效果庫中選擇傾斜效果,而’oblique’是程式對字型做的傾斜處理 |
fontweight | 字型大小,可以是0-1000的一個數值,也可以是字串{‘ultralight’, ‘light’, ‘normal’, ‘regular’, ‘book’, ‘medium’, ‘roman’, ‘semibold’, ‘demibold’, ‘demi’, ‘bold’, ‘heavy’, ‘extra bold’, ‘black’ |
horizontalalignment | 水平對齊樣式選擇,可以選擇{‘center’, ‘right’, ‘left’} |
verticalalignment | 垂直對齊,可以選擇{‘center’, ‘top’, ‘bottom’, ‘baseline’, ‘center_baseline’} |
引數名 | 介紹 |
---|---|
nrows, ncols | 分割的行數和列數 |
sharex, sharey | 設定是否共享座標軸,取值為 bool or {‘none’, ‘all’, ‘row’, ‘col’} |
squeeze | 規定是否將1 * M和 N * 1的分割也作為二維陣列返回 |
subplot_kw | 可以設定為字典型別,其中的引數作為add_subplot函式的引數傳遞到每個子區域中 |
gridspec_kw | |
ax | Axes型別的陣列,用於規定每個子區域的格式,詳見下文 |
在此我們只規定行數和列數,其他遵循預設設定:
axs = fig.subplots(2, 4)
條形圖的繪製和引數設定
引數名 | 介紹 |
---|---|
x | 橫座標的值序列 |
height | 用於規定條形圖的高度的序列 |
width | 規定條形圖每個資料條的寬度,以比例形式給出,預設0.8 |
bottom | 規定y座標軸以什麼值為最小值顯示在圖中 |
align | 資料條的對齊方式,可選{‘center’, ‘edge’},其中‘edge’為左對齊,右對齊可以通過設定width引數為負來實現 |
color | 規定每個資料條的顏色(包含edgecolor和facecolor) |
facecolor | 資料條內部的顏色 |
edgecolor | 資料條邊框的顏色 |
linewidth | 資料條邊緣的寬度 |
tick_lable | 規定資料條的刻度標籤,預設為數值標籤 |
hatch | 用於填充的樣式,可選有{’/’, ‘’, ’ |
我們據此建立一個柱狀圖:
axs[0][0].bar(yearList, pointsList, hatch='+', color='#FFD700', edgecolor='#8B0A50')
我們又通過以下語句設定了座標軸的範圍和精度,並在資料條上方顯示具體資料:
axs[0][0].set_yticks(np.arange(0, 35, 3))
axs[0][0].set_xlim(2003, 2018)
for a, b in zip(yearList, pointsList):
axs[0][0].text(a, b, b,
horizontalalignment='center', verticalalignment='baseline',
fontdict=fontNum)
即y軸的範圍為0至35,精度為3,x軸為2003至2018;
其中fontdict通過字典格式設定了字型樣式,一般格式如下:
fontTitle = {
'family': 'fantasy',
'color': '#FFD700',
'weight': 'demibold',
'size': 14
}
axs[0][0].set_title('Average Points', fontdict=fontTitle)
四項分別設定了字型族、顏色、粗細和大小,我們用它設定了分標題,最終第一個子區域如下:
以此方法繪製所有子區域的條形圖:
axs[0][0].set_title('Average Points', fontdict=fontTitle)
axs[0][0].bar(yearList, pointsList, hatch='+', color='#FFD700', edgecolor='#8B0A50')
axs[0][0].set_yticks(np.arange(0, 35, 3))
axs[0][0].set_xlim(2003, 2018)
for a, b in zip(yearList, pointsList):
axs[0][0].text(a, b, b,
horizontalalignment='center', verticalalignment='baseline',
fontdict=fontNum)
axs[0][1].set_title('Average Rebounds', fontdict=fontTitle)
axs[0][1].bar(yearList, reboundsList, hatch='O', color='#FFD700', edgecolor='#8B0A50')
axs[0][1].set_yticks(np.arange(0, 9, 1))
axs[0][1].set_xlim(2003, 2018)
for a, b in zip(yearList, reboundsList):
axs[0][1].text(a, b, b,
horizontalalignment='center', verticalalignment='baseline',
fontdict=fontNum)
axs[0][2].set_title("Average Assists", fontdict=fontTitle)
axs[0][2].bar(yearList, assistsList, hatch='|', color='#FFD700', edgecolor='#8B0A50')
axs[0][2].set_yticks(np.arange(0, 9, 1))
axs[0][2].set_xlim(2003, 2018)
for a, b in zip(yearList, assistsList):
axs[0][2].text(a, b, b,
horizontalalignment='center', verticalalignment='baseline',
fontdict=fontNum)
axs[0][3].set_title("Average Steals", fontdict=fontTitle)
axs[0][3].bar(yearList, stealsList, hatch='X', color='#FFD700', edgecolor='#8B0A50')
axs[0][3].set_yticks(np.arange(0, 2.5, 0.25))
axs[0][3].set_xlim(2003, 2018)
for a, b in zip(yearList, stealsList):
axs[0][3].text(a, b, b,
horizontalalignment='center', verticalalignment='baseline',
fontdict=fontNum)
axs[1][0].set_title("Average Blocks", fontdict=fontTitle)
axs[1][0].bar(yearList, blocksList, hatch='*', color='#FFD700', edgecolor='#8B0A50')
axs[1][0].set_yticks(np.arange(0, 1.4, 0.1))
axs[1][0].set_xlim(2003, 2018)
for a, b in zip(yearList, blocksList):
axs[1][0].text(a, b, b,
horizontalalignment='center', verticalalignment='baseline',
fontdict=fontNum)
axs[1][1].set_title("Field Goals Percent", fontdict=fontTitle)
axs[1][1].bar(yearList, fieldPercentList, hatch='.', color='#FFD700', edgecolor='#8B0A50')
axs[1][1].set_yticks(np.arange(0, 0.7, 0.05))
axs[1][1].set_xlim(2003, 2018)
for a, b in zip(yearList, fieldPercentList):
axs[1][1].text(a, b, b,
horizontalalignment='center', verticalalignment='baseline',
fontdict=fontNum)
axs[1][2].set_title("ThreePoint Goals Percent", fontdict=fontTitle)
axs[1][2].bar(yearList, threePercentList, hatch='/', color='#FFD700', edgecolor='#8B0A50')
axs[1][2].set_yticks(np.arange(0, 0.5, 0.05))
axs[1][2].set_xlim(2003, 2018)
for a, b in zip(yearList, threePercentList):
axs[1][2].text(a, b, b,
horizontalalignment='center', verticalalignment='baseline',
fontdict=fontNum)
axs[1][3].set_title("Games Attended", fontdict=fontTitle)
axs[1][3].bar(yearList, gamesList, hatch='-', color='#FFD700', edgecolor='#8B0A50')
axs[1][3].set_yticks(np.arange(0, 85, 5))
axs[1][3].set_xlim(2003, 2018)
for a, b in zip(yearList, gamesList):
axs[1][3].text(a, b, b,
horizontalalignment='center', verticalalignment='baseline',
fontdict=fontNum)
儲存影象
plt.savefig('D:/SparkProjects/NBADataBase/data/lebron_statsfig.png', facecolor='#CD00CD')
plt.show()
注意一點,若想在儲存圖片之後檢視圖片,應將show放在savefig之後,因savefig函式執行之後會將plot重置為白色。
最終效果如下,湖人配色的勒布朗生涯技術統計,還算可以吧: