1. 程式人生 > >勒布朗生涯資料視覺化(二)用Matplotlib製作柱形圖及Figure, Text類和bar函式的引數探索

勒布朗生涯資料視覺化(二)用Matplotlib製作柱形圖及Figure, Text類和bar函式的引數探索

簡介

  • 本篇文章使用Kaggle.com上的資料集NBA Players stats since 1950中的Seasons_Stats.csv,其包含從1950至今的每個賽季的球員資料,每條資料有53項欄目,是綜合性較強的NBA資料集,我嘗試從中提取勒布朗詹姆斯的生涯資料,並用Matplotlib庫實現視覺化功能。
  • 第二部分中我們使用第一部分檢索出來的相關資料,並繪製出定制樣式的柱形圖,效果如下:
    Lebron

配置

  • 語言: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)

四項分別設定了字型族、顏色、粗細和大小,我們用它設定了分標題,最終第一個子區域如下:
points以此方法繪製所有子區域的條形圖:

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重置為白色。

最終效果如下,湖人配色的勒布朗生涯技術統計,還算可以吧:
Lebron

參考資料