開源一個 topn 詞競賽影片專案 topn_race:
- GitCode 倉庫:https://gitcode.net/csdn/topn_race
核心功能:
- 輸入:按月統計的topN詞頻資料
- 輸出:topN詞頻競賽影片(可帶音效)
原始碼結構
本專案基于開源專案:https://github.com/dexplo/bar_chart_race 定制,src/bar_chart_race 從 bar_chart_race 專案的源代碼修改以適配需求,
依賴庫:
progress==1.5
matplotlib==3.4.2
pandas==1.2.4
numpy==1.19.5
moviepy==1.0.3
原始碼結構:
.
├── LICENSE
├── README.md
├── data
│ ├── csdn_ask_top10_month
│ │ ├── 2008-05-01.json
│ │ ├── 2008-06-01.json
│ │ ├── ...
│ └── csdn_trends_top10_month
│ └── csdn_index_top_10.csv
├── demo
│ ├── csdn_ask_top10_month.gif
│ ├── csdn_trends_top10_month.gif
│ └── demo.md
├── main.py
├── pub
│ ├── ...
├── requirements.txt
└── src
├── bar_chart_race
│ ├── __init__.py
│ ├── chart.py
│ └── colormaps.py
├── common
│ ├── __init__.py
│ ├── error.py
│ ├── gif.py
│ ├── json.py
│ ├── path.py
│ ├── random.py
│ └── utils.py
└── top.py
其中:
main.py是測驗程式入口- src/top.py 是 topN 競賽影片的邏輯組織控制層
- src/common 提供了一些基本的utils
- src/bar_chart_race 從 bar_chart_race 專案的源代碼修改以適配需求
- 基本樣式的內部調整
- 使用漫畫風格
代碼說明
基本用法如下:
def test_build_csdn_trend_top10_tag_race():
input = InputMeta(
type='csv',
path='data/csdn_trends_top10_month/csdn_index_top_10.csv',
month_field='date',
name_field='tag_name',
count_field='index_value',
audio='pub/mali.mp3'
)
output = OutputMeta(
path='pub/csdn_trends_top10_month',
ext='gif',
title='CSDN topN指數月排行榜',
x_label='csdn.net/trends',
y_label='指數',
month_count=None
)
top = Top(input, output)
top.build()
Top 類的建構式傳入兩個引數:input: InputMeta 和output: OutputMeta,很多Python代碼的引數能有幾十個引數,通過InputMeta 和 OutputMeta 兩個dataclass可以讓使用更友好:
@dataclass
class InputMeta:
'''
type: 指定型別,如果是 "json_str" 表示一個JSON檔案夾,如果是"csv"表示一個csv檔案
JSON 檔案夾:
約定每個檔案的檔案名是月份,每個JSON檔案是一個陣列,陣列元素是標簽統計資訊
name_field: 指定標簽名字的欄位名
count_field: 指定標簽月份統計資訊的欄位名
CSV 檔案
month_field: 指定月份欄位
name_field: 指定標簽名字的欄位名
count_field: 指定標簽月份統計資訊的欄位名
audio: 音頻
'''
type: str
path: str
month_field: str
name_field: str
count_field: str
audio: str
@dataclass
class OutputMeta:
'''
輸出配置
path: 輸出路徑
title: 標題
x_label: X軸名字
y_label: Y軸名字
month_count: 繪制月份,用來除錯,使用較少的月份快速查看輸出效果
'''
path: str
ext: str
title: str
x_label: str
y_label: str
month_count: int
Top 類的 build 里的處理流程包括:
- 轉換輸入資料到每月一行的 DataFrame
- 每12個月資料生成一個競賽動圖 GIF
- 原因之一:太大的GIF檔案生成會有記憶體占用問題,分片處理,
- 原因之二:分片后,規避出錯時要從頭再來的問題,
- 合并多個GIF,生成一個MP4檔案
- 如果輸入指定了音頻檔案,使用音頻源采用repeat方式與MP4合成軌道并輸出帶音效的檔案
輸出目錄pub下的檔案不提交到git倉庫,需要注意的是,構建程序中不同平臺上的中文字體會有差異,目前適配了Mac和Linux的字體,其他平臺待測驗,
實體:CSDN topN 指數月排行榜競賽動圖
CSDN指數
CSDN 指數是基于自 2000 年以來 CSDN 平臺產生的海量內容資料、用戶行為計算而來,作為中國最大專業 IT 技術社區,CSDN 指數具備高度權威性,您可通過查詢關鍵字,用以進行技術領域趨勢分析、技術選型變遷歷史探索、技術內容消費特征洞察、開發者崗位需求預測等,
我們用 CSDN 指數的資料做了一個topN 指數月排行榜競賽動圖
競賽影片部分片段GIF:

完整版本請看:
- CSDN topN指數 月排行榜競賽影片(2000.1-2021.12)獨立視頻
- CSDN topN指數 月排行榜競賽影片(2000.1-2021.12)社區帖子
資料可視化
資料經過可視化處理后,可以發現資料間的規律,歡迎對專案提交貢獻,開箱即用的漫畫風格topN競賽動圖:https://gitcode.net/csdn/topn_race
這個專案在6月份的時候做過一個版本,對問答的歷年標簽月排行榜做了一次渲染,當時一次性跑資料渲染比較久,這次再做的時候想到了一個原因應該是同一個GIF整體渲染可能會導致性能越來越慢,于是第一個改進的思路就是分片渲染,再做合成,
分片操作的程序中,也會順便產生滿足多種需要的輸出考慮,例如最后一片的最后一幀會增加停留時長,避免動圖到最后一幀一閃而過;例如最后一片也會生成一個小于5M的摘要GIF,用來寫博客的時候上傳片段GIF使用:
class Top:
...
def build(self):
...
max_rows = self.df.shape[0]
i = 0
j = 0
df = self.df
gifs = []
os.makedirs(self.output, exist_ok=True)
while i < max_rows:
end = i+12
if end >= max_rows:
end = max_rows+1
step = end-i
filename = os.path.join(self.output, f'{j}.{self.ext}')
if i+step >= max_rows:
# 最后一個
last_df = df[i:end]
# 生成一個短摘要
min_half = 5
if min_half > last_df.shape[0]:
min_half = 0
self.df = last_df[min_half:]
filename_abstracts = os.path.join(
self.output, f'{j}_abstracts.{self.ext}')
self.__build_race(filename_abstracts)
# 加強最后一幀
self.df = last_df
for k in range(0, 12):
self.df = self.df.append(df[end-2:end])
self.__build_race(filename)
else:
self.df = df[i:end]
self.__build_race(filename)
gifs.append(filename)
i += step
j += 1
其次很多這樣的庫包含一堆的引數,例如 topn_race 下層使用的原始庫bar_chart_race的代碼就是這樣的,實際上這里有一個經典的設計模式是可以解決此類代碼的組織問題:Builder模式,我覺的后續改進是可以改造下它的代碼,不要用一堆的建構式引數讓使用者很難用,通過Builder模式是可以輕易對同一個庫的不同使用情景做模塊化介面設計,這塊后面可以用來進一步改造bar_chart_race的代碼,Python 代碼越是靈活,越是要在寫的程序中注意簡潔的基礎上有好的設計,
一個多道程式的內部會有很多重要的實際干活的重型關節代碼,如果沒有一些控制邏輯,多次運行不能保持輕量,會讓人害怕,舉個例子,渲染的多個關鍵環節,都應該加入一些規避不必要的重復操作的判定邏輯:
例如,判定檔案已存在,是否需要覆寫,這樣你就可以放心的多次操作
class Top:
...
def build(self):
...
# 合并 gif 生成mp4
all = f'{self.output}.mp4'
if os.path.exists(all):
ret = input(f"檔案:{all}已存在,是否覆寫?[y/n]:")
if ret == 'y':
concat_gif_list(gifs, all)
else:
concat_gif_list(gifs, all)
潛在需求
- 完備的全平臺字體支持
- 支持為條形圖增加關聯的「彈幕文本」
- 增加片頭和片尾渲染(保持很短),讓它接近代碼微電影
- 進一步解決性能問題
- 使用Flask支持服務化,支持在線部署和呼叫
–end–
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/398594.html
標籤:AI
下一篇:vlan原理與基礎配置
