<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>

          讓數(shù)據(jù)動起來!用Python制作動畫可視化效果,讓數(shù)據(jù)不再枯燥!

          共 33280字,需瀏覽 67分鐘

           ·

          2021-05-21 17:27


          通常大家做出來的圖表,絕大部分都是靜態(tài)的,有時會顯得不夠吸引人。


          今天小F就給大家介紹一下,如何用Python繪制動態(tài)圖表。


          主要是使用到Matplotlib+imageio,其中Matplotlib就有一個Animation類,可以生成動圖GIF,不過使用起來學習成本較高,還是有一定難度的。


          這里我將先創(chuàng)建靜態(tài)圖表的圖片,然后使用Imageio創(chuàng)建一個GIF(動態(tài)圖表)。


          一共給大家介紹三種動態(tài)圖表的繪制,折線圖,條形圖,散點圖。



          01 折線圖


          先來繪制一個簡單的折線圖看看。


          import os
          import numpy as np
          import matplotlib.pyplot as plt
          import imageio

          # 生成40個取值在30-40的數(shù)
          y = np.random.randint(3040, size=(40))
          # 繪制折線
          plt.plot(y)
          # 設置y軸最小值和最大值
          plt.ylim(2050)

          # 顯示
          plt.show()


          使用Numpy創(chuàng)建一個數(shù)值范圍在30到40之間的隨機整數(shù)列表,結果如下。



          下面將對整數(shù)列表進行切片,生成不同階段的圖表。


          # 第一張圖
          plt.plot(y[:-3])
          plt.ylim(2050)
          plt.savefig('1.png')
          plt.show()

          # 第二張圖
          plt.plot(y[:-2])
          plt.ylim(2050)
          plt.savefig('2.png')
          plt.show()

          # 第三張圖
          plt.plot(y[:-1])
          plt.ylim(2050)
          plt.savefig('3.png')
          plt.show()

          # 第四張圖
          plt.plot(y)
          plt.ylim(2050)
          plt.savefig('4.png')
          plt.show()


          得到x軸為0:36、0:37、0:38、0:39四個折線圖表。



          有了這四張圖,我們就可以使用Imageio生成GIF了。


          # 生成Gif
          with imageio.get_writer('mygif.gif', mode='I'as writer:
              for filename in ['1.png''2.png''3.png''4.png']:
                  image = imageio.imread(filename)
                  writer.append_data(image)


          動圖來了。



          一個會動的折線圖表就制作出來了,過不是從x軸坐標為0的時候開始的。


          filenames = []
          num = 0
          for i in y:
              num += 1
              # 繪制40張折線圖
              plt.plot(y[:num])
              plt.ylim(2050)

              # 保存圖片文件
              filename = f'{num}.png'
              filenames.append(filename)
              plt.savefig(filename)
              plt.close()

          # 生成gif
          with imageio.get_writer('mygif.gif', mode='I'as writer:
              for filename in filenames:
                  image = imageio.imread(filename)
                  writer.append_data(image)

          # 刪除40張折線圖
          for filename in set(filenames):
              os.remove(filename)


          繪制出40張折線圖,并且保存圖片,生成GIF。


          可以看到折線圖的x坐標從0一直到了40。


          02 條形圖


          上面的折線圖每次只有一個y值即可,而條形圖則需要所有的y值,如此所有的條形才能同時移動。

          給X軸創(chuàng)建固定值,Y軸創(chuàng)建列表,并使用Matplotlib的條形圖函數(shù)。

          x = [12345]
          coordinates_lists = [[00000],
                               [1030603010],
                               [7040204070],
                               [1020304050],
                               [5040302010],
                               [75075075],
                               [00000]]
          filenames = []
          for index, y in enumerate(coordinates_lists):
              # 條形圖
              plt.bar(x, y)
              plt.ylim(080)

              # 保存圖片文件
              filename = f'{index}.png'
              filenames.append(filename)

              # 重復最后一張圖形15幀(數(shù)值都為0),15張圖片
              if (index == len(coordinates_lists) - 1):
                  for i in range(15):
                      filenames.append(filename)

              # 保存
              plt.savefig(filename)
              plt.close()

          # 生成gif
          with imageio.get_writer('mygif.gif', mode='I'as writer:
              for filename in filenames:
                  image = imageio.imread(filename)
                  writer.append_data(image)

          # 刪除20張柱狀圖
          for filename in set(filenames):
              os.remove(filename)


          有數(shù)值的條形圖圖片是5張,沒數(shù)值的圖片是2+15=17張。


          GIF結束段,添加了15幀空白圖片。所以在結束的時候會顯示一段時間的空白。

          可以設置一下條形圖當前位置到下個位置的速度,讓過渡變得平滑

          將當前位置和下一個位置之間的距離除以過渡幀數(shù)。

          n_frames = 10
          x = [12345]
          coordinates_lists = [[00000],
                               [1030603010],
                               [7040204070],
                               [1020304050],
                               [5040302010],
                               [75075075],
                               [00000]]
          print('生成圖表\n')
          filenames = []
          for index in np.arange(0, len(coordinates_lists) - 1):
              # 獲取當前圖像及下一圖像的y軸坐標值
              y = coordinates_lists[index]
              y1 = coordinates_lists[index + 1]

              # 計算當前圖像與下一圖像y軸坐標差值
              y_path = np.array(y1) - np.array(y)
              for i in np.arange(0, n_frames + 1):
                  # 分配每幀的y軸移動距離
                  # 逐幀增加y軸的坐標值
                  y_temp = (y + (y_path / n_frames) * i)
                  # 繪制條形圖
                  plt.bar(x, y_temp)
                  plt.ylim(080)
                  # 保存每一幀的圖像
                  filename = f'images/frame_{index}_{i}.png'
                  filenames.append(filename)
                  # 最后一幀重復,畫面停留一會
                  if (i == n_frames):
                      for i in range(5):
                          filenames.append(filename)
                  # 保存圖片
                  plt.savefig(filename)
                  plt.close()
          print('保存圖表\n')
          # 生成GIF
          print('生成GIF\n')
          with imageio.get_writer('mybars.gif', mode='I'as writer:
              for filename in filenames:
                  image = imageio.imread(filename)
                  writer.append_data(image)
          print('保存GIF\n')
          print('刪除圖片\n')
          # 刪除圖片
          for filename in set(filenames):
              os.remove(filename)
          print('完成')


          看起來是平滑了許多。


          好了,接下來我們更改一下圖表相關的配置參數(shù),讓圖表變得好看。

          n_frames = 10
          bg_color = '#95A4AD'
          bar_color = '#283F4E'
          gif_name = 'bars'
          x = [12345]
          coordinates_lists = [[00000],
                               [1030603010],
                               [7040204070],
                               [1020304050],
                               [5040302010],
                               [75075075],
                               [00000]]
          print('生成圖表\n')
          filenames = []
          for index in np.arange(0, len(coordinates_lists) - 1):
              y = coordinates_lists[index]
              y1 = coordinates_lists[index + 1]
              y_path = np.array(y1) - np.array(y)
              for i in np.arange(0, n_frames + 1):
                  y_temp = (y + (y_path / n_frames) * i)
                  # 繪制條形圖
                  fig, ax = plt.subplots(figsize=(84))
                  ax.set_facecolor(bg_color)
                  plt.bar(x, y_temp, width=0.4, color=bar_color)
                  plt.ylim(080)
                  # 移除圖表的上邊框和右邊框
                  ax.spines['right'].set_visible(False)
                  ax.spines['top'].set_visible(False)
                  # 設置虛線網(wǎng)格線
                  ax.set_axisbelow(True)
                  ax.yaxis.grid(color='gray', linestyle='dashed', alpha=0.7)
                  # 保存每一幀的圖像
                  filename = f'images/frame_{index}_{i}.png'
                  filenames.append(filename)

                  # 最后一幀重復,畫面停留一會
                  if (i == n_frames):
                      for i in range(5):
                          filenames.append(filename)
                  # 保存圖片
                  plt.savefig(filename, dpi=96, facecolor=bg_color)
                  plt.close()
          print('保存圖表\n')
          # 生成GIF
          print('生成GIF\n')
          with imageio.get_writer(f'{gif_name}.gif', mode='I'as writer:
              for filename in filenames:
                  image = imageio.imread(filename)
                  writer.append_data(image)
          print('保存GIF\n')
          print('刪除圖片\n')
          # 刪除圖片
          for filename in set(filenames):
              os.remove(filename)
          print('完成')


          給圖表添加了背景色、條形圖上色、去除邊框、增加網(wǎng)格線等。


          看起來,效果還不錯!

          當然也有一些值得改進的地方,比如添加標題。通過插值的方式來使過渡變得更平滑,甚至可以讓條形圖在x軸上移動。

          這里大家就可以自行去研究啦。


          03 散點圖

          要繪制動態(tài)散點圖,則需要同時考慮x軸和y軸的值。

          這里不一定要在每幀上顯示相同數(shù)量的點,因此需要對其進行校正來進行過渡。

              
          coordinates_lists = [[[0], [0]],
                               [[100200300], [100200300]],
                               [[400500600], [400500600]],
                               [[400500600400500600], [400500600600500400]],
                               [[500], [500]],
                               [[0], [0]]]
          gif_name = 'movie'
          n_frames = 10
          bg_color = '#95A4AD'
          marker_color = '#283F4E'
          marker_size = 25
          print('生成圖表\n')
          filenames = []
          for index in np.arange(0, len(coordinates_lists) - 1):
              # 獲取當前圖像及下一圖像的x與y軸坐標值
              x = coordinates_lists[index][0]
              y = coordinates_lists[index][1]
              x1 = coordinates_lists[index + 1][0]
              y1 = coordinates_lists[index + 1][1]
              # 查看兩點差值
              while len(x) < len(x1):
                  diff = len(x1) - len(x)
                  x = x + x[:diff]
                  y = y + y[:diff]
              while len(x1) < len(x):
                  diff = len(x) - len(x1)
                  x1 = x1 + x1[:diff]
                  y1 = y1 + y1[:diff]
              # 計算路徑
              x_path = np.array(x1) - np.array(x)
              y_path = np.array(y1) - np.array(y)
              for i in np.arange(0, n_frames + 1):
                  # 計算當前位置
                  x_temp = (x + (x_path / n_frames) * i)
                  y_temp = (y + (y_path / n_frames) * i)
                  # 繪制圖表
                  fig, ax = plt.subplots(figsize=(66), subplot_kw=dict(aspect="equal"))
                  ax.set_facecolor(bg_color)

                  plt.scatter(x_temp, y_temp, c=marker_color, s=marker_size)
                  plt.xlim(01000)
                  plt.ylim(01000)
                  # 移除邊框線
                  ax.spines['right'].set_visible(False)
                  ax.spines['top'].set_visible(False)
                  # 網(wǎng)格線
                  ax.set_axisbelow(True)
                  ax.yaxis.grid(color='gray', linestyle='dashed', alpha=0.7)
                  ax.xaxis.grid(color='gray', linestyle='dashed', alpha=0.7)
                  # 保存圖片
                  filename = f'images/frame_{index}_{i}.png'
                  filenames.append(filename)
                  if (i == n_frames):
                      for i in range(5):
                          filenames.append(filename)
                  # 保存
                  plt.savefig(filename, dpi=96, facecolor=bg_color)
                  plt.close()
          print('保存圖表\n')
          # 生成GIF
          print('生成GIF\n')
          with imageio.get_writer(f'{gif_name}.gif', mode='I'as writer:
              for filename in filenames:
                  image = imageio.imread(filename)
                  writer.append_data(image)
          print('保存GIF\n')
          print('刪除圖片\n')
          # 刪除圖片
          for filename in set(filenames):
              os.remove(filename)
          print('完成')

          效果如下。


          當然還有更有趣的散點圖變化,比如字母變化。

          使用OpenCV從圖像創(chuàng)建mask,繪制填充有隨機x/y坐標的圖,并過濾mask內(nèi)的點。 

          使用Matplotlib繪制散點圖,使用ImageIO生成gif。

              
          import os
          import numpy as np
          import matplotlib.pyplot as plt
          import imageio
          import random
          import cv2


          # 根據(jù)字母的形狀, 將字母轉化為多個隨機點
          def get_masked_data(letter, intensity=2):
              # 多個隨機點填充字母
              random.seed(420)
              x = []
              y = []

              for i in range(intensity):
                  x = x + random.sample(range(01000), 500)
                  y = y + random.sample(range(01000), 500)

              if letter == ' ':
                  return x, y

              # 獲取圖片的mask
              mask = cv2.imread(f'images/letters/{letter.upper()}.png'0)
              mask = cv2.flip(mask, 0)

              # 檢測點是否在mask中
              result_x = []
              result_y = []
              for i in range(len(x)):
                  if (mask[y[i]][x[i]]) == 0:
                      result_x.append(x[i])
                      result_y.append(y[i])

              # 返回x,y
              return result_x, result_y


          # 將文字切割成一個個字母
          def text_to_data(txt, repeat=True, intensity=2):
              print('將文本轉換為數(shù)據(jù)\n')
              letters = []
              for i in txt.upper():
                  letters.append(get_masked_data(i, intensity=intensity))
              # 如果repeat為1時,重復第一個字母
              if repeat:
                  letters.append(get_masked_data(txt[0], intensity=intensity))
              return letters


          def build_gif(coordinates_lists, gif_name='movie', n_frames=10, bg_color='#95A4AD',
                        marker_color='#283F4E', marker_size=25)
          :

              print('生成圖表\n')
              filenames = []
              for index in np.arange(0, len(coordinates_lists) - 1):
                  # 獲取當前圖像及下一圖像的x與y軸坐標值
                  x = coordinates_lists[index][0]
                  y = coordinates_lists[index][1]

                  x1 = coordinates_lists[index + 1][0]
                  y1 = coordinates_lists[index + 1][1]

                  # 查看兩點差值
                  while len(x) < len(x1):
                      diff = len(x1) - len(x)
                      x = x + x[:diff]
                      y = y + y[:diff]

                  while len(x1) < len(x):
                      diff = len(x) - len(x1)
                      x1 = x1 + x1[:diff]
                      y1 = y1 + y1[:diff]

                  # 計算路徑
                  x_path = np.array(x1) - np.array(x)
                  y_path = np.array(y1) - np.array(y)

                  for i in np.arange(0, n_frames + 1):
                      # 計算當前位置
                      x_temp = (x + (x_path / n_frames) * i)
                      y_temp = (y + (y_path / n_frames) * i)

                      # 繪制圖表
                      fig, ax = plt.subplots(figsize=(66), subplot_kw=dict(aspect="equal"))
                      ax.set_facecolor(bg_color)
                      plt.xticks([])  # 去掉x軸
                      plt.yticks([])  # 去掉y軸
                      plt.axis('off')  # 去掉坐標軸

                      plt.scatter(x_temp, y_temp, c=marker_color, s=marker_size)

                      plt.xlim(01000)
                      plt.ylim(01000)

                      # 移除框線
                      ax.spines['right'].set_visible(False)
                      ax.spines['top'].set_visible(False)

                      # 網(wǎng)格線
                      ax.set_axisbelow(True)
                      ax.yaxis.grid(color='gray', linestyle='dashed', alpha=0.7)
                      ax.xaxis.grid(color='gray', linestyle='dashed', alpha=0.7)

                      # 保存圖片
                      filename = f'images/frame_{index}_{i}.png'

                      if (i == n_frames):
                          for i in range(5):
                              filenames.append(filename)

                      filenames.append(filename)

                      # 保存
                      plt.savefig(filename, dpi=96, facecolor=bg_color)
                      plt.close()
              print('保存圖表\n')
              # 生成GIF
              print('生成GIF\n')
              with imageio.get_writer(f'{gif_name}.gif', mode='I'as writer:
                  for filename in filenames:
                      image = imageio.imread(filename)
                      writer.append_data(image)
              print('保存GIF\n')
              print('刪除圖片\n')
              # 刪除圖片
              for filename in set(filenames):
                  os.remove(filename)

              print('完成')


          coordinates_lists = text_to_data('Python', repeat=True, intensity=50)

          build_gif(coordinates_lists,
                    gif_name='Python',
                    n_frames=7,
                    bg_color='#52A9F0',
                    marker_color='#000000',
                    marker_size=0.2)

          生成一個Python單詞字母的動態(tài)散點圖。


          三個主要的函數(shù)。

          # 創(chuàng)建一個隨機的x/y坐標列表,并使用mask對其進行過濾。
          get_masked_data()
          # 將文本轉化為數(shù)據(jù)
          text_to_data()
          # 使用坐標點生成散點圖, 保存GIF
          build_gif()


          這里小F給大家提供了26個字母,大伙可以自行組合。

          當然其他圖形也是可以的,就是需要自己作圖。

          圖片的大小應為1000x1000像素,mask著色為黑色,背景為白色。

          然后png文件保存在images/letters文件夾中,單獨一個字符命名

          coordinates_lists = text_to_data('mac_', repeat=True, intensity=50)

          build_gif(coordinates_lists,
                    gif_name='mac',
                    n_frames=7,
                    bg_color='#F5B63F',
                    marker_color='#000000',
                    marker_size=0.2)


          結果如下,最后一張是個人物像。


          好了,本期的分享就到此結束了。

          使用Matplotlib+Imageio創(chuàng)建動態(tài)圖表,案例比較簡單,大家可以自行下載代碼進行學習。


          最后在公眾號回復「動畫」,獲取到本次使用到的代碼和數(shù)據(jù)




              


          推薦閱讀:

          入門: 最全的零基礎學Python的問題  | 零基礎學了8個月的Python  | 實戰(zhàn)項目 |學Python就是這條捷徑


          干貨:爬取豆瓣短評,電影《后來的我們》 | 38年NBA最佳球員分析 |   從萬眾期待到口碑撲街!唐探3令人失望  | 笑看新倚天屠龍記 | 燈謎答題王 |用Python做個海量小姐姐素描圖 |碟中諜這么火,我用機器學習做個迷你推薦系統(tǒng)電影


          趣味:彈球游戲  | 九宮格  | 漂亮的花 | 兩百行Python《天天酷跑》游戲!


          AI: 會做詩的機器人 | 給圖片上色 | 預測收入 | 碟中諜這么火,我用機器學習做個迷你推薦系統(tǒng)電影


          小工具: Pdf轉Word,輕松搞定表格和水印! | 一鍵把html網(wǎng)頁保存為pdf!|  再見PDF提取收費! | 用90行代碼打造最強PDF轉換器,word、PPT、excel、markdown、html一鍵轉換 | 制作一款釘釘?shù)蛢r機票提示器! |60行代碼做了一個語音壁紙切換器天天看小姐姐!


          年度爆款文案


                                  
                                     
                                       
                                        

                                        
                                        
                                        
          點閱讀原文,領廖雪峰視頻資料!

          瀏覽 34
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <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>
                  青娱乐精品自拍偷拍 | 麻豆视频免费观看 | 视频免费一区 | 国产无码免费 | 大香蕉伊人免费在线观看 |