首頁>技術>

Python資料分析:零基礎入門教學(講解+實戰)

https://www.bilibili.com/video/BV18f4y1i7q9/
前言

上個月的時候看到一張很漂亮的商業圖,很喜歡,然後就忘了。剛好前兩天看到一篇文章來臨摹此圖,於是學習了一下其思路和程式碼,然後拿來實踐了一下,效果還可以,特此紀念,以後應該還有用得上的地方。那商業圖我就不放了,然後把我的圖放在這裡↓

資料準備

可以看到,圖中主要有4列資料組成,分別是公司logo、公司名稱、所屬工具和市值增長值。於是先準備資料,就是我常用的軟體工具列舉了一下,共20個,然後數值是使用率吧,Type是用來標記顏色的,最後一列分類是次軟體的主要作用,&符號連線兩個或多個主要用途。如下↓

import matplotlib.pyplot as pltimport pandas as pdimport osos.chdir(r'E:\Python\Seaborn\Others')mydata = pd.read_excel('不規則條形圖資料.xlsx')

設定中文字型正常顯示

mycolor = {    'Green': '#8ABD25',    'Pink': '#F57FEF',    'Yellow': '#EBE639',    'Red': '#EB3939',    'Orange': '#EBAF39',    'Blue': '#39A4EB',    'Black': '#4D6E83',    'Gray': '#A3A4A5',}

自定義顏色,後面直接根據Type型別進行呼叫就行了

logosize = 0.037 #軟體圖示大小right_height = 20 #右邊矩形填充的高度,建議和資料行數一樣多ratio = 0.05 #這個係數會影響右邊矩形整體的偏移情況,建議值是(1/行數)ratio2 = 0.8 #這個係數影響右邊矩形上面的下移程度ratio3 = 0.005 #分類圖示的水平位置ratio4 = 0.01 #數影響右邊矩形下面的上移程度ratio5 = 0.01 #影響軟體文字的上下水平

一些影響的引數,因為涉及多處,所以提出來統一修改了,還有一些引數需要裡面改。

def create_fill_area(row):    # 初始化包圍填充區域的上下線條y座標    line1, line2 = [1 - ratio*row, 1 - ratio*row], [1- ratio*(row+1), 1- ratio*(row+1)]    # 追加陰影段y座標    line1.append(ratio4 + (right_height - row) * (ratio2 - ratio4) / right_height)    line2.append(ratio4 + (right_height - row - 1) * (ratio2 - ratio4) / right_height)    # 追加最後一段平行段y座標    line1.append(ratio4 + (right_height - row) * (ratio2 - ratio4) / right_height)    line2.append(ratio4 + (right_height - row - 1) * (ratio2 - ratio4) / right_height)    return line1, line2

為了創建出不同條帶,配合matplotlib中的fill_between。為了處理好左側與右側的豎直方向等分割槽域,我們可以在對原資料每一行迴圈的過程中,自定義下列函式來計算區域範圍↓

fig, ax = plt.subplots(figsize=(4.8, 6))ax.set_xlim(0, 1.11)ax.set_ylim(0, 1)for row in range(mydata.shape[0]):    # 定義區域填充對應的x座標    x = [0, 0.15, 0.215, 0.6+mydata.at[row, 'Values'] / 1000]    # 生成區域填充對應的y座標    line1, line2 = create_fill_area(row)    # 對指定區域進行填充    ax.fill_between(x,                    line1,                    line2,                    color=mycolor[mydata.at[row, 'Type']],                    edgecolor='none')        # 從logo資料夾下讀取對應logo圖片    try:        logo = plt.imread(f'logo/{mydata.at[row, "Tools"]}.png')    except FileNotFoundError:        logo = plt.imread(f'logo/{mydata.at[row, "Tools"]}.jpg')        # 插入軟體logo    ax_logo = ax.inset_axes((0.05, 1 - ratio*(row+1)+0.005, 0.08, logosize))    ax_logo.imshow(logo)        ax_logo.axis('off')    ax_logo.set_facecolor(mycolor[mydata.at[row, 'Type']])        # 處理單個及多個功能情況下的繪製    for idx, Category in enumerate(mydata.at[row, 'Category'].split('&')[::-1]):                # 讀取對應功能圖片        flag = plt.imread(f'flag/{Category}.png')        # 插入功能子圖        ax_flag = ax.inset_axes((0.545-idx*0.06, 0.013+(right_height - row - 1)*((ratio2 - ratio3) / right_height), 0.1, 0.025))        ax_flag.imshow(flag)        ax_flag.axis('off')        ax_flag.set_facecolor(mycolor[mydata.at[row, 'Type']])    # 繪製排名    ax.text(0.025, (1 - ratio*row + 1 - ratio*(row+1)) / 2, str(row+1),             ha='center', va='center',            fontsize=9, color='black')    # 繪製軟體名稱    ax.text(0.215+ratio5, 0.5 * (ratio5 + (right_height - row - 1) * (ratio2 - ratio5) / right_height + ratio5 + (right_height - row) * (ratio2 - ratio5) / right_height),             mydata.at[row, 'Tools'],             ha='left', va='center',            fontsize=9, color='#FFFFFF',             weight='bold')    # 處理第一名文字在填充區域內部,其餘文字在填充區域外的情況    if mydata.at[row, 'Tools'] == 'Exce1l':        ax.text(1, 0.5 * (ratio3 + (right_height - row) * (ratio2 - ratio3) / right_height                           + ratio3 + (right_height - row - 1) * (ratio2 - ratio3) / right_height)-0.0025,                ''+str(mydata.at[row, 'Values']/4)+'%',                color='white',                fontsize=10,                ha='right',                va='center',                weight='bold')    else:        # 配合歸一化對字型進行大小對映        ax.text(0.6+mydata.at[row, 'Values'] / 1000 + ratio3,                 0.5 * (ratio3 + (right_height - row) * (ratio2 - ratio3) / right_height + ratio3 + (right_height - row - 1) * (ratio2 - ratio3) / right_height)-0.0025,                ''+str(int(mydata.at[row, 'Values']/4))+'%',                color=mycolor[mydata.at[row, 'Type']],                fontsize=7+((mydata.at[row, 'Values'] - mydata['Values'].min())                             / (mydata['Values'].max() - mydata['Values'].min())) * 5,                ha='left',                va='center',                weight='bold')# 對指定區域進行帶透明度的黑色蒙版,以達到陰影效果ax.fill_between([0.15, 0.215],                [0, ratio4],                [1, ratio2],                color='black',                alpha=0.2, # 設定透明度                edgecolor='none')# 補充其餘文字標註ax.text(0.215+ratio5, 0.805, '軟體名稱',         color='#565555', fontsize=6,        ha='left')ax.text(0.67, 0.805, '軟體型別',         color='#565555', fontsize=6,        ha='center')#補充上方數值刻度ax.text(0.6, 0.825, '0',         color='#a9a8a8', fontsize=8,        ha='center')    for i in range(1, 5):    print(i)    ax.text(0.6+0.1*i, 0.825, f'{i*25}%',             color='#a9a8a8', fontsize=9,            ha='center')       ax.vlines(0.6+0.1*i, 0.01, 0.82,               color='#dcdcdb', linewidth=0.2)ax.set_xticks([])ax.set_yticks([])ax.spines['left'].set_color('none')ax.spines['right'].set_color('none')ax.spines['top'].set_color('none')ax.spines['bottom'].set_color('none')# 補充下排圖例ax_bar1 = ax.inset_axes((0.215, 0.88, 0.57, 0.02), transform=ax.transAxes)ax_bar1.set_xlim(-0.45, 3.6)ax_bar1.bar(range(4), height=1, width=0.8,             color=['#8ABD25', '#F57FEF', '#EBE639', '#EB3939'])ax_bar1.set_xticks(range(4))ax_bar1.set_xticklabels(['綠色系', '紫色系', '黃色系', '紅色系'],                        fontsize=7, color='#4f4e4e', weight='bold')ax_bar1.set_yticks([])ax_bar1.spines['left'].set_color('none')ax_bar1.spines['right'].set_color('none')ax_bar1.spines['top'].set_color('none')ax_bar1.spines['bottom'].set_color('none')ax_bar1.tick_params(color='none', pad=-2)ax_bar1.set_facecolor('#f8f8f8')# 補充上排圖例ax_bar2 = ax.inset_axes((0.215, 0.98, 0.57, 0.02), transform=ax.transAxes)ax_bar2.set_xlim(-0.45, 3.6)ax_bar2.bar(range(4), height=1, width=0.8,             color=['#EBAF39', '#39A4EB', '#4D6E83', '#A3A4A5'])ax_bar2.set_xticks(range(4))ax_bar2.set_xticklabels(['橙色系', '藍色系', '黑色系', '灰色系'],                        fontsize=7, color='#4f4e4e', weight='bold')ax_bar2.set_yticks([])ax_bar2.spines['left'].set_color('none')ax_bar2.spines['right'].set_color('none')ax_bar2.spines['top'].set_color('none')ax_bar2.spines['bottom'].set_color('none')ax_bar2.tick_params(color='none', pad=-2)ax_bar2.set_facecolor('#f8f8f8')ax.set_facecolor('#f8f8f8')fig.set_facecolor('#f8f8f8')fig.savefig('輸出結果.png', dpi=800, bbox_inches='tight')

下面是繪圖程式碼,都有註釋說明,讀一遍應該都能讀懂,只是一些巧妙計算的邏輯需要理一下。這裡沒有繪製標題,可以藉助PS新增一個完美的標題。

fig, ax = plt.subplots(figsize=(4.8, 6))ax.set_xlim(0, 1.11)ax.set_ylim(0, 1)for row in range(mydata.shape[0]):    # 定義區域填充對應的x座標    x = [0, 0.15, 0.215, 0.6+mydata.at[row, 'Values'] / 1000]    # 生成區域填充對應的y座標    line1, line2 = create_fill_area(row)    # 對指定區域進行填充    ax.fill_between(x,                    line1,                    line2,                    color=mycolor[mydata.at[row, 'Type']],                    edgecolor='none')        # 從logo資料夾下讀取對應logo圖片    try:        logo = plt.imread(f'logo/{mydata.at[row, "Tools"]}.png')    except FileNotFoundError:        logo = plt.imread(f'logo/{mydata.at[row, "Tools"]}.jpg')        # 插入軟體logo    ax_logo = ax.inset_axes((0.05, 1 - ratio*(row+1)+0.005, 0.08, logosize))    ax_logo.imshow(logo)        ax_logo.axis('off')    ax_logo.set_facecolor(mycolor[mydata.at[row, 'Type']])        # 處理單個及多個功能情況下的繪製    for idx, Category in enumerate(mydata.at[row, 'Category'].split('&')[::-1]):                # 讀取對應功能圖片        flag = plt.imread(f'flag/{Category}.png')        # 插入功能子圖        ax_flag = ax.inset_axes((0.545-idx*0.06, 0.013+(right_height - row - 1)*((ratio2 - ratio3) / right_height), 0.1, 0.025))        ax_flag.imshow(flag)        ax_flag.axis('off')        ax_flag.set_facecolor(mycolor[mydata.at[row, 'Type']])    # 繪製排名    ax.text(0.025, (1 - ratio*row + 1 - ratio*(row+1)) / 2, str(row+1),             ha='center', va='center',            fontsize=9, color='black')    # 繪製軟體名稱    ax.text(0.215+ratio5, 0.5 * (ratio5 + (right_height - row - 1) * (ratio2 - ratio5) / right_height + ratio5 + (right_height - row) * (ratio2 - ratio5) / right_height),             mydata.at[row, 'Tools'],             ha='left', va='center',            fontsize=9, color='#FFFFFF',             weight='bold')    # 處理第一名文字在填充區域內部,其餘文字在填充區域外的情況    if mydata.at[row, 'Tools'] == 'Exce1l':        ax.text(1, 0.5 * (ratio3 + (right_height - row) * (ratio2 - ratio3) / right_height                           + ratio3 + (right_height - row - 1) * (ratio2 - ratio3) / right_height)-0.0025,                ''+str(mydata.at[row, 'Values']/4)+'%',                color='white',                fontsize=10,                ha='right',                va='center',                weight='bold')    else:        # 配合歸一化對字型進行大小對映        ax.text(0.6+mydata.at[row, 'Values'] / 1000 + ratio3,                 0.5 * (ratio3 + (right_height - row) * (ratio2 - ratio3) / right_height + ratio3 + (right_height - row - 1) * (ratio2 - ratio3) / right_height)-0.0025,                ''+str(int(mydata.at[row, 'Values']/4))+'%',                color=mycolor[mydata.at[row, 'Type']],                fontsize=7+((mydata.at[row, 'Values'] - mydata['Values'].min())                             / (mydata['Values'].max() - mydata['Values'].min())) * 5,                ha='left',                va='center',                weight='bold')# 對指定區域進行帶透明度的黑色蒙版,以達到陰影效果ax.fill_between([0.15, 0.215],                [0, ratio4],                [1, ratio2],                color='black',                alpha=0.2, # 設定透明度                edgecolor='none')# 補充其餘文字標註ax.text(0.215+ratio5, 0.805, '軟體名稱',         color='#565555', fontsize=6,        ha='left')ax.text(0.67, 0.805, '軟體型別',         color='#565555', fontsize=6,        ha='center')#補充上方數值刻度ax.text(0.6, 0.825, '0',         color='#a9a8a8', fontsize=8,        ha='center')    for i in range(1, 5):    print(i)    ax.text(0.6+0.1*i, 0.825, f'{i*25}%',             color='#a9a8a8', fontsize=9,            ha='center')       ax.vlines(0.6+0.1*i, 0.01, 0.82,               color='#dcdcdb', linewidth=0.2)ax.set_xticks([])ax.set_yticks([])ax.spines['left'].set_color('none')ax.spines['right'].set_color('none')ax.spines['top'].set_color('none')ax.spines['bottom'].set_color('none')# 補充下排圖例ax_bar1 = ax.inset_axes((0.215, 0.88, 0.57, 0.02), transform=ax.transAxes)ax_bar1.set_xlim(-0.45, 3.6)ax_bar1.bar(range(4), height=1, width=0.8,             color=['#8ABD25', '#F57FEF', '#EBE639', '#EB3939'])ax_bar1.set_xticks(range(4))ax_bar1.set_xticklabels(['綠色系', '紫色系', '黃色系', '紅色系'],                        fontsize=7, color='#4f4e4e', weight='bold')ax_bar1.set_yticks([])ax_bar1.spines['left'].set_color('none')ax_bar1.spines['right'].set_color('none')ax_bar1.spines['top'].set_color('none')ax_bar1.spines['bottom'].set_color('none')ax_bar1.tick_params(color='none', pad=-2)ax_bar1.set_facecolor('#f8f8f8')# 補充上排圖例ax_bar2 = ax.inset_axes((0.215, 0.98, 0.57, 0.02), transform=ax.transAxes)ax_bar2.set_xlim(-0.45, 3.6)ax_bar2.bar(range(4), height=1, width=0.8,             color=['#EBAF39', '#39A4EB', '#4D6E83', '#A3A4A5'])ax_bar2.set_xticks(range(4))ax_bar2.set_xticklabels(['橙色系', '藍色系', '黑色系', '灰色系'],                        fontsize=7, color='#4f4e4e', weight='bold')ax_bar2.set_yticks([])ax_bar2.spines['left'].set_color('none')ax_bar2.spines['right'].set_color('none')ax_bar2.spines['top'].set_color('none')ax_bar2.spines['bottom'].set_color('none')ax_bar2.tick_params(color='none', pad=-2)ax_bar2.set_facecolor('#f8f8f8')ax.set_facecolor('#f8f8f8')fig.set_facecolor('#f8f8f8')fig.savefig('輸出結果.png', dpi=800, bbox_inches='tight')

這個顏色有點豔麗,可以調整一下顏色就行了,然後用PS加個標題,底部再加點看不懂的小文字顯得高階,然後基本上就大功告成了。

17
  • BSA-TRITC(10mg/ml) TRITC-BSA 牛血清白蛋白改性標記羅丹明
  • Python 開發:製作一個簡易的點菜系統(附原始碼)