<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          Matplotlib玩轉(zhuǎn)動態(tài)可視化

          共 5627字,需瀏覽 12分鐘

           ·

          2020-09-16 01:13

          最近看到很多盆友們用pyecharts、Bokeh和plotly等繪圖庫制作動態(tài)圖,還有用pbi制作的,以及網(wǎng)頁工具flourish等。其實(shí)matplotlib這個經(jīng)典繪圖庫也是可以的,這不就來了嘛~

          目錄

          • 1.效果預(yù)覽
          • 2.數(shù)據(jù)獲取
          • 3.數(shù)據(jù)預(yù)處理
          • 4.matplotlib動態(tài)可視化

          1.效果預(yù)覽

          我們從國家統(tǒng)計(jì)局 下載最近30年全國各地區(qū)生產(chǎn)總值(實(shí)際上是1993年-2019年),使用matplotlib繪制動態(tài)可視化圖,效果如下:

          2.數(shù)據(jù)獲取

          直接從國家統(tǒng)計(jì)局-「國家數(shù)據(jù)」(http://data.stats.gov.cn/)下載原始數(shù)據(jù)即可,數(shù)據(jù)長這樣:

          3.數(shù)據(jù)預(yù)處理

          #?需要引入的庫
          import?pandas?as?pd
          import?matplotlib.pyplot?as?plt
          import?matplotlib.ticker?as?ticker
          import?matplotlib.animation?as?animation
          from?IPython.display?import?HTML

          原始數(shù)據(jù)的行索引是地區(qū),列索引是年份,我們后續(xù)作圖需要的數(shù)據(jù)結(jié)構(gòu)偏向于窄表(當(dāng)然寬表其實(shí)也可以做到,這里我個人習(xí)慣用窄表處理)。

          為了實(shí)現(xiàn)寬表變窄表,用到pandas里的melt方法。

          import?pandas?as?pd
          #?讀取下載后的數(shù)據(jù)
          df?=?pd.read_excel(r'F:\微信公眾號\matplotlib動態(tài)圖\各地區(qū)生產(chǎn)總值.xlsx')
          df.head()
          #?使用melt方法進(jìn)行處理
          data?=?df.melt(id_vars='地區(qū)',value_vars=range(1993,2020),var_name='年份',value_name='生產(chǎn)總值(億)')
          data.head()

          4.matplotlib動態(tài)可視化

          matplotlib動態(tài)圖用到的是animation.FuncAnimation方法,其實(shí)動態(tài)就是N張圖一張一張按照一定頻率刷新,我們也有其他方法實(shí)現(xiàn),這里不展開。

          在我們的效果展示中,可以看到 類型是條形圖,數(shù)值高低排序,每個條形圖顏色不一樣,我們來一步一步看看如何做出最終效果~

          4.1.樸實(shí)無華的條形圖

          barh是條形圖,就是橫著的柱狀圖,以下我們先取2019年的年度數(shù)據(jù)展示前10地區(qū)

          import?matplotlib.pyplot?as?plt
          import?matplotlib.ticker?as?ticker
          #?以下代碼解決顯示中文問題
          plt.rcParams['font.sans-serif']?=?['SimHei']
          #?繪制?2019年?各地區(qū)生產(chǎn)總值(前10)
          currentYear?=?2019
          ddata?=?(data[data['年份']==currentYear]
          ????????.sort_values(by='生產(chǎn)總值(億)',ascending?=?True)
          ????????.tail(10))
          fix,?ax?=?plt.subplots(figsize=(15,8))
          ax.barh(ddata['地區(qū)'],?ddata['生產(chǎn)總值(億)'])

          我們看到上面這張圖平平無奇,樸實(shí)無華的配色,沒有多一分的元素(標(biāo)題、數(shù)據(jù)標(biāo)簽等等),接下來我們先把條形圖美化一下

          4.2.有點(diǎn)還行的條形圖

          通過自定義條形圖配色,再附上一些text說明。

          關(guān)于配色,直接從網(wǎng)上(https://www.beejson.com/word/rgb.html)找 16進(jìn)制配色表,然后取31個即可(咱們一共有31個地區(qū)數(shù)據(jù)不含港澳臺)。然后將31個地區(qū)與31個顏色進(jìn)行組合成字典備用!

          「構(gòu)造地區(qū)-顏色字典」

          #?我直接從網(wǎng)上批量復(fù)制了?30多個顏色值,然后隨機(jī)抽取31個和31個地區(qū)配對
          a?=?['#FFFFCC??#FFCC00??#CC9909??#663300??#FF6600??#663333??#CC6666??#FF6666??#FF0000??#FFFF99??#FFCC66??#FF9900??#FF9966??#CC3300??#996666??#FFCCCC??#660000??#FF3300??#FF6666??#FFCC33??#CC6600??#FF6633??#996633??#CC9999??#FF3333??#990000??#CC9966??#FFFF33??#CC9933??#993300??#FF9933??#330000??#993333??#CC3333??#CC0000??#FFCC99??#FFFF00??#996600']
          b?='?'.join(a)
          c?=?b.split('?\t')

          import?random
          #?隨機(jī)不放回抽取31個
          color?=?random.sample(c,31)
          #?獲取原數(shù)據(jù)中地區(qū)列表
          province?=?list(data['地區(qū)'].unique())
          #?組合成?地區(qū)-顏色值?字典
          colors?=?dict(zip(province,color))

          「繪制有顏的條形圖」

          fig,?ax?=?plt.subplots(figsize=(15,8))
          ax.barh(ddata['地區(qū)'],?ddata['生產(chǎn)總值(億)'],color?=?[colors[x]?for?x?in?ddata['地區(qū)']])
          #?在每個條形圖末端顯示?歸屬地區(qū)?及?生產(chǎn)總值(億)
          for?i,?(num,?pro)?in?enumerate(zip(ddata['生產(chǎn)總值(億)'],?ddata['地區(qū)'])):
          ????ax.text(num,i,?pro,?ha?=?'right')
          ????ax.text(num,i,?f':{num}億',?ha?=?'left')
          #?在右側(cè)中部偏下顯示當(dāng)前年份
          ax.text(1,?0.4,?currentYear,?transform=?ax.transAxes,?size=40,?ha='right')
          Text(1,?0.4,?'2019')

          有人就要說了,上面這個圖也沒啥好看的,除了增加了單獨(dú)的配色以及數(shù)據(jù)顯示外。。講的太對了,字體還丑、顏色搭配也是難看,當(dāng)然這些都是可以自己配置的 因?yàn)楹罄m(xù) 我們會換個plt.xkcd()**「手繪卡通風(fēng)格」**的形式,但是卡通風(fēng)格的形式需要特別處理中文字體顯示問題,這里先介紹下來自好朋友 「'小明哥'」 的幫助,如下代碼(設(shè)置字體為我系統(tǒng)里的微軟雅黑,字號16)

          #?字體管理
          from?matplotlib?import?font_manager
          my_font?=?font_manager.FontProperties(fname=r"C:\Windows\Fonts\msyh.ttc",size=14)
          #?再加入其他一些元素(如標(biāo)題、刻度線、刻度放在最上方等)
          fig,?ax?=?plt.subplots(figsize=(15,8))
          ax.barh(ddata['地區(qū)'],?ddata['生產(chǎn)總值(億)'],color?=?[colors[x]?for?x?in?ddata['地區(qū)']])

          for?i,?(num,?pro)?in?enumerate(zip(ddata['生產(chǎn)總值(億)'],?ddata['地區(qū)'])):
          ????ax.text(num,i,?pro,?ha?=?'right',fontproperties=my_font)
          ????ax.text(num,i,?f'?:{num}億',?ha?=?'left',fontproperties=my_font)

          ax.text(1,?0.4,?currentYear,?transform=?ax.transAxes,fontproperties=my_font,?size=40,?ha='right')

          #?x刻度設(shè)置在頂部
          ax.xaxis.set_ticks_position('top')
          #?x刻度顏色設(shè)置為灰色,大小為12
          ax.tick_params(axis=?'x',colors=?'#777777',labelsize=?12)
          #?去掉y刻度
          ax.set_yticks([])
          #?設(shè)置?xy軸內(nèi)邊距
          ax.margins(0,?0.01)
          #?顯示網(wǎng)格(x軸向虛線)
          ax.grid(which=?'major',?axis=?'x',linestyle=?'--')
          #?網(wǎng)格線至于底部
          ax.set_axisbelow(True)
          #?在左上角顯示?標(biāo)題(不是用的title方法)
          ax.text(0,?1.06,'全國各地區(qū)生產(chǎn)總值(1993-2019)',transform=?ax.transAxes,weight?=600,ha?=?'left',fontproperties=?my_font,size=24)
          #?去掉邊框
          plt.box(False)

          4.3.會動的條形圖

          既然動圖是一張張圖刷新而來,那我們把每年的數(shù)據(jù)都做一張圖再定時刷新替換不就好了,這樣當(dāng)然是可以的。

          所以,我們先看看「animation.FuncAnimation」(https://matplotlib.org/api/animation_api.html)吧

          官網(wǎng)有個簡單的例子:sin(x)的動態(tài)演示。這里不做介紹,源碼清晰,我們直接現(xiàn)學(xué)現(xiàn)做~

          先把上面作圖代碼封裝成函數(shù)

          這個函數(shù)只需要一個參數(shù),year(年份)

          fig,?ax?=?plt.subplots(figsize=(12,16))
          def?drawBarh(year):
          ????ddata?=?(data[data['年份']==year]
          ????????.sort_values(by='生產(chǎn)總值(億)',ascending?=?True)
          ????????.tail(31))
          ????ax.clear()
          ????
          ????ax.barh(ddata['地區(qū)'],?ddata['生產(chǎn)總值(億)'],color?=?[colors[x]?for?x?in?ddata['地區(qū)']])

          ????for?i,?(num,?pro)?in?enumerate(zip(ddata['生產(chǎn)總值(億)'],?ddata['地區(qū)'])):
          ????????ax.text(num,i,?pro,?ha?=?'right',fontproperties=my_font)
          ????????ax.text(num,i,?f'?:{num}億',?ha?=?'left',fontproperties=my_font)

          ????ax.text(1,?0.4,?year,?transform=?ax.transAxes,fontproperties=my_font,?size=40,?ha='right')

          ????#?x刻度設(shè)置在頂部
          ????ax.xaxis.set_ticks_position('top')
          ????#?x刻度顏色設(shè)置為灰色,大小為12
          ????ax.tick_params(axis=?'x',colors=?'#777777',labelsize=?12)
          ????#?去掉y刻度
          ????ax.set_yticks([])
          ????#?設(shè)置?xy軸內(nèi)邊距
          ????ax.margins(0,?0.01)
          ????#?顯示網(wǎng)格(x軸向虛線)
          ????ax.grid(which=?'major',?axis=?'x',linestyle=?'--')
          ????#?網(wǎng)格線至于底部
          ????ax.set_axisbelow(True)
          ????#?在左上角顯示?標(biāo)題(不是用的title方法)
          ????ax.text(0,?1.06,'全國各地區(qū)生產(chǎn)總值(1993-2019)',transform=?ax.transAxes,weight?=600,ha?=?'left',fontproperties=?my_font,size=24)
          ????#?去掉邊框
          ????plt.box(False)

          #?演示2019年數(shù)據(jù)
          drawBarh(2019)

          animation動圖制作

          再調(diào)用animation.FuncAnimation方法進(jìn)行動圖制作,我們在輸出的頁面可以進(jìn)行動畫演示(快捷、后退、開始、暫停等等)。

          fig?,ax?=plt.subplots(figsize?=?(12,16))
          #?手繪卡通風(fēng)格
          plt.xkcd()
          animator?=?animation.FuncAnimation(fig,drawBarh,frames=range(1993,2020),interval=500)
          HTML(animator.to_jshtml())
          #?通過以下方式可以保存為動圖(保存為視頻方式我們單獨(dú)介紹吧)
          animator.save('生產(chǎn)總值動態(tài)圖.gif',bitrate=1800,writer?='pillow')
          ?

          「交流與思考」:我們在效果動圖中發(fā)現(xiàn)其實(shí)沒那么順滑,這是因?yàn)槲覀兪前凑彰恳荒甑臄?shù)據(jù)繪制一次導(dǎo)致的,那么如何讓效果更加順滑呢?

          (一般來說,可以把每年的數(shù)據(jù)分為多份,比如我們認(rèn)為每兩年之間存在N組值,那么就是有N-2個缺失值,通過pandas的缺失值插值處理可以補(bǔ)充一些值作為繪圖的輔助值,從而讓效果更加順滑,那么如何進(jìn)行插值呢?pandas其實(shí)有現(xiàn)成的方式,這里也不展開說明了)

          ?

          -END-



          瀏覽 60
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  sese97sese | 一级二级三级毛片 | 91蜜桃 | 五十路激情 | 激情毛片网 |