Python 數(shù)據(jù)可視化:繪制柱形圖和條形圖

從本課開始,依次介紹常用的一些統(tǒng)計圖表,以下引用來自維基百科中的“統(tǒng)計圖表”詞條部分內(nèi)容。

圖表(Chart),或又稱為統(tǒng)計圖表,代表了一張圖像化的數(shù)據(jù),并經(jīng)常以所用的圖像命名,例如圓餅圖,是主要使用圓形符號,長條圖或直方圖,則主要使用長方形符號。折線圖,意味著使用線條符號。

常見的圖表包括:直方圖(Histogram)、長條圖(Bar Chart)、餅圖(Pie Chart)、折線圖(Line Chart)等。

1.5.1 柱形圖

柱形圖,還稱為長條圖、條圖、條狀圖、棒形圖、柱狀圖,長條圖,英文中可以使用“bar graph”或者“bar chart”。

柱形圖基本樣式如下圖所示,它是一種以柱子高度為變量的統(tǒng)計圖表。在柱形圖中可以直觀地觀察到某些變量之間的相對大小關(guān)系。通常,柱形圖適用于較小的數(shù)據(jù)集,如果數(shù)據(jù)集的維度太多,會造成“柱子”太密集,失去了可視化的效果。

%matplotlib inline
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt

position = ['apple', 'facebook', 'google', 'huawei', 'alibaba']
data = [56, 65, 98, 73, 86]
plt.bar(x=position, height=data)

輸出結(jié)果:

enter image description here

繪制柱形圖所使用的函數(shù)為 plt.bar,其完整形式如下:

plt.bar(x, height, width=0.8, bottom=None, *, align='center', data=None, **kwargs)

下面對若干常用參數(shù)進行解釋:

  • x,坐標(biāo)系的橫坐標(biāo)
  • height,柱子的高度
  • width,柱子的寬度
  • bottom,柱子底部與 x 軸之間的距離
  • align,可選值為 'center' 或 'edge',設(shè)置 x 軸橫坐標(biāo)的主刻線與柱子的中央對齊,還是與邊緣對齊
  • color,柱子的顏色
  • edgecolor,柱子邊緣的顏色
  • linewidth,柱子邊線的寬度,如果為 0,則沒有邊線
  • tick_label,橫坐標(biāo)刻線的標(biāo)示,如果不設(shè)置,則默認(rèn)為數(shù)字

再使用 plt.bar 制圖,加深對某些參數(shù)的理解,特別注意觀察參數(shù)的值和輸出結(jié)果,并與上面的輸出結(jié)果對比。

plt.bar(x=position, height=data, width=0.4, bottom=[10,7,0,5,3], color='red', linewidth=5)
plt.grid(True)

輸出結(jié)果:

image

除了使用 plt.bar 之外,前面曾經(jīng)提過,在 pandas 的 DataFrame 對象下,有專門繪圖的方法,柱形圖就可以這樣來實現(xiàn)。

df = pd.DataFrame({"position":position, 'data':data})
df.plot.bar(x='position', y='data')

輸出結(jié)果:

enter image description here

上述柱形圖比較的是單個變量(維度、特征)之間的大小關(guān)系,在此基礎(chǔ)上,還可以用一種稱為“堆積柱形圖”的方式,展示每個變量(維度、特征)內(nèi)部的各元素比例。

下面看一個示例,是對近年全國暑期票房收入的統(tǒng)計(僅統(tǒng)計歷年 8 月份),借此理解“堆積柱形圖”的繪制和應(yīng)用。

首先本例所用數(shù)據(jù)來自 Tushare,如果讀者愿意使用第三方模塊獲得數(shù)據(jù),請安裝:pip3 install Tushare,然后按照如下演示得到數(shù)據(jù)。但是,這個模塊的官方在讀者閱讀的時候或許已經(jīng)修改了讀取數(shù)據(jù)的政策,若用下面的方式?jīng)]有得到數(shù)據(jù),請到官方網(wǎng)站查閱最新政策。另外,為了方便學(xué)習(xí),我把以下示例用到的數(shù)據(jù)整理到了數(shù)據(jù)倉庫,可以將此數(shù)據(jù)下載到本地,然后用pd.read_csv函數(shù)加載。

import tushare as ts
box_office = pd.DataFrame()
for y in range(2010, 2019):    # 2010年(含)至2018年(含)
    ym = str(y) + '-8'
    df = ts.month_boxoffice(ym)
    box_office[ym] = df['boxoffice']
box_office

# output
    2010-8  2011-8  2012-8  2013-8  2014-8  2015-8  2016-8  2017-8  2018-8
0    26918   39162   27993   63665   39313   73427   98811   424006  132009
1    17760   30890   23051   29567   36338   54977   58144   53419   122078
2    8816    22919   15020   29460   28981   48912   38770   49087   102581
3    8125    17219   14636   17121   20807   20948   38675   34147   68285
4    5157    6243    13518   16468   18746   19542   34589   29012   55460
5    5133    5326    8895    14473   18714   18083   26931   23652   32013
6    3980    3594    7037    11416   16926   17220   16663   16825   23011
7    2655    3410    6868    7542    9770    14643   15334   15806   19543
8    2581    3301    4159    6286    9729    14458   14736   12588   17830
9    2233    1954    3471    5440    9464    9977    8376    11341   15238
10    8245    13137   17216   24674   53426   69576   54576   66712   93990

然后計算每年的票房總收入。

box_office = box_office.astype(np.int)    # 將數(shù)據(jù)類型轉(zhuǎn)化為整數(shù)型
total = box_office.sum()
total

# output
2010-8     91603
2011-8    147155
2012-8    141864
2013-8    226112
2014-8    262214
2015-8    361763
2016-8    405605
2017-8    736595
2018-8    682038
dtype: int64

接下來才是激動人心的時刻,先貼出代碼和結(jié)果,再慢慢品味。

import matplotlib.ticker as ticker

first = box_office.iloc[0].astype(np.int)    # 歷年票房第一
after_first = total - first    # 其他影片票房收入

date_index = pd.to_datetime(total.index)
fig, ax = plt.subplots()
ax.grid(color='gray')

ax.bar(range(1, 10), after_first.values, label='others')    # ①
ax.bar(range(1, 10), first.values, bottom=after_first.values, label='first')    # ②

ax.set_xticks(range(0, 10))   # ③
ax.xaxis.set_major_formatter(ticker.IndexFormatter([0]+date_index.year.tolist()))    # ④

plt.legend(loc=0)

輸出結(jié)果:

image

先觀察輸出結(jié)果的圖示,從中都可以讀出什么信息?

  • 基本上票房收入在一直增加,2017 年 8 月份是歷年 8 月份的最高峰,2018 年則略有下降。
  • 再看每年票房收入第一的影片在當(dāng)年總收入中所占比重,顯然 2017 年的是凸點,這年影片票房收入的頭部效應(yīng)非常顯著,而其他影片的票房收入相比上一年并沒有太多增加。

2017 年票房第一的就是那部高揚民族主義大旗的動作片《戰(zhàn)狼2》,據(jù)娛樂新聞報道后來也得補稅。

看電影的時候熱血沸騰,但研究科學(xué)問題,還是要靜下心來?!翱茖W(xué)技術(shù)是第一生產(chǎn)力”,再鼓舞士氣的電影,也不如扎扎實實的生產(chǎn)力發(fā)展。因此,建議讀者,還是要認(rèn)真研究程序中的每個語句,這才是真正民族崛起的保證。

① 和 ② 兩個語句,是在坐標(biāo)系中繪制柱形圖,它們的差別在于 ① 中沒有設(shè)置 bottom 參數(shù),② 中有 bottom = after_first.values,從而實現(xiàn)票房收入第一的和當(dāng)年其他影片收入成為“堆積柱”,兩者的總高度是該年的總票房收入。

注意,語句 ③ 和 ④ 是用來設(shè)置橫坐標(biāo)的主刻線以及相應(yīng)的標(biāo)示,特別是在 ④ 中,使用了 matplotlib.ticker 中的 IndexFormatter 類得到標(biāo)示對象。

堆積柱形圖可以看做是柱形圖的拓展,此外,還有被稱為“簇狀柱形圖”的拓展,即將若干個柱形圖作為一簇,在每一簇中,柱子和柱子之間的距離小于簇與簇之間的距離,通常將簇內(nèi)各柱子之間距離設(shè)置為 0。

position = np.arange(1, 6)
a = np.random.random(5)
b = np.random.random(5)

total_width = 0.8    
n = 2
width = total_width / n
position = position - (total_width - width) / n    # ⑤

plt.bar(position, a, width=width, label='a', color='b')    # ⑥
plt.bar(position + width, b, width=width, label='b', color='r')    # ⑦

plt.legend(loc=0)

輸出結(jié)果:

image

語句 ⑤ 計算除了每簇的中央位置,這個很重要,請揣摩一下它的數(shù)學(xué)表達式含義。

語句 ⑥ 和 ⑦ 分別繪制每簇中的兩個柱子,因為每簇中柱子之間的距離是 0,所以在 ⑦ 中用 position + width 表示第二根柱子的中央線位置。

對于繪制“簇狀柱形圖”,如果直接使用 DataFrame 對象的方法,可以更簡單。例如:

speed = [0.1, 17.5, 40, 48, 52, 69, 88]
lifespan = [2, 8, 70, 1.5, 25, 12, 28]
index = ['snail', 'pig', 'elephant', 'rabbit', 'giraffe', 'coyote', 'horse']
df = pd.DataFrame({'speed': speed,'lifespan': lifespan}, index=index)
ax = df.plot.bar(rot=0)

還有 51% 的精彩內(nèi)容
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。
支付 ¥2.99 繼續(xù)閱讀

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容