前言
本文的文字及圖片來源于網路,僅供學習、交流使用,不具有任何商業用途,著作權歸原作者所有,如有問題請及時聯系我們以作處理,
荔枝 | 作者
Crossin的編程教室 | 來源
1. 需求
做股票分析的朋友經常會見到類似這種的期貨公司持倉榜單圖:
這種圖就是棒棒糖圖,也就是我們今天文章的目標:
繪制出期貨持倉榜單的棒棒糖圖
圖中線的兩端是圓點或者菱形,旁邊都有標注持倉證券商和相對應的持多倉數或持空倉數,且左右線顏色不同,畫圖思路大體就是:先畫水平線圖,再用 scatter 散點圖畫線左右兩端的點,然后標注兩端名稱,以及標題和注解,
Python 中比較常用的兩種圖表庫是 matplotlib 和 plotly,上圖就是以 matplotlib 繪制,而 Plotly 互動性更好,
更進一步,如果想讓用戶可以點擊選擇交易日期,查看該日期對應的榜單圖,這就可以通過一個回應式 web 應用程式來實作,Dash 是一個基于 python 的互動式可視化 web 應用框架,matplotlib 和 Plotly 都可與 Dash 框架結合使用,
Matplotlib 大家比較熟悉,在開始之前,我們先簡單介紹下 plotly 和 Dash,
2. Plotly
plotly 庫(plotly.py)是一個互動式的開源繪圖庫,支持40多種獨特的圖表型別,涵蓋各種統計,財務,地理,科學和三維用例,是適用于Python,R 和 JavaScript 的互動式圖表庫,
plotly.py 建立在 Plotly JavaScript 庫(plotly.js)之上,使Python用戶可以創建基于 Web 的漂亮互動式可視化效果,這些可視化效果可以顯示在 Jupyter 筆記本中,可以保存到獨立的 HTML 檔案中,也可以作為純 Python 使用,其官方檔案上提供了各種圖示的介面說明,
3. Dash
Dash 是用于構建 Web 應用程式的 Python 框架,Dash 建立在 Flask、Plotly.js 和 React.js 基礎之上,即 Dash 中的控制元件和其觸發事件都是用 React.js 包裝的,Plotly.js 為 Dash 提供強大的互動式資料可視化圖庫,Flask 為其提供后端框架,這個框架對 python 程式員特別友好,只需要寫 python 代碼,不需要寫 JS 代碼,直接拖拽控制元件來用即可,感興趣的童鞋可以去 Dash 的官方檔案多多了解一下,Dash 是使用純 Python 構建高度自定義用戶界面的資料可視化應用程式的理想選擇,它特別適合做資料分析、資料可視化以及儀表盤或者報告展示,可以將 Dash 應用程式部署到服務器,然后通過 URL 共享它們,不受平臺和環境的限制,
4. 安裝
在畫圖之前,我們需要裝一下 Dash、plotly 相關包,可以用 pip 裝:
pip install plotly dash
或者也可以用 conda 進行安裝,
5. 資料格式和資料處理
測驗資料來自東方財富網,用 csv 檔案格式保存,
資料的格式如下,header 是日期為第一列,第3列往后為期貨公司名字,表格中的負數是上面圖中藍色的空倉,正數是紅色的多倉,繪圖時,從表格中取出某一日期的一行記錄,將持倉數目排序,把對應的資料存入串列中,之后進行畫圖,
首先對資料進行清洗和處理, pandas讀取資料,這里需要去除 000905_SH 列,以及洗掉全0行,代碼如下:
excel_pd = pd.read_excel('data/IC期貨商歷史資料(1).xlsx', index_col='日期') # 去空 excel_pd.dropna() # 去除000905_SH列 excel_pd = excel_pd.drop(labels='000905_SH', axis=1) # 去0行 excel_pd = excel_pd[~(excel_pd == 0).all(axis=1)] # 取出時間串列,獲取最大日期和最小日期,為日歷選項做判斷 date_list = excel_pd.index.values.tolist() min_date = min(date_list) max_date = max(date_list)
接下來我們需要根據輸入的日期來篩選某一行記錄,分別將持空倉期貨公司和持多倉期貨公司取出,剔除持倉數為0的期貨公司,代碼如下:
def get_data_via_date_from_excel(date): # 篩選日期 sheet1_data =https://www.cnblogs.com/hhh188764/p/ excel_pd.loc[date] # 去除列值為0 sheet1_data = https://www.cnblogs.com/hhh188764/p/sheet1_data[sheet1_data != 0] # 排序 從小到大 sheet1_data =https://www.cnblogs.com/hhh188764/p/ sheet1_data.sort_values() # 空倉 short_hold = sheet1_data[sheet1_data < 0] # 多倉 long_hold = sheet1_data[sheet1_data >= 0].sort_values(ascending=False) return short_hold, long_hold
6. 畫圖
Matplotlib畫圖
創建一張畫布figure和ax畫圖層,用ax.hlines分別畫空倉水平線和多倉水平線,用ax.scatter畫左右兩邊線的散點,使用菱形marker,使用plt.text分別畫線兩端的標注期貨公司和持倉數,plt.annotate畫排名標注,分別設定顏色和字體大小,
但這個效果是反的,我們是希望排名最前面的在上,排名最后面的下,這時我們可以設定y軸反置一下ax.invert_yaxis(),添加圖例和標題以及設定坐標軸不可見,得到最終效果:
核心代碼如下:
def draw_lollipop_graph(short_hold, long_hold, date): # sheet_major.index.values.tolist() fig, ax = plt.subplots(figsize=(10, 8)) # 空倉水平線 ax.hlines(y=[i for i in range(len(short_hold))], xmin=list(short_hold), xmax=[0] * len(short_hold.index), color='#1a68cc', label='空') # 多倉水平線 ax.hlines(y=[i for i in range(len(long_hold))], xmax=list(long_hold), xmin=[0] * len(long_hold.index), color='red', label='多') # 畫散點 ax.scatter(x=list(short_hold), y=[i for i in range(len(short_hold))], s=10, marker='d', edgecolors="#1a68cc", zorder=2, color='white') # zorder設定該點覆寫線 ax.scatter(x=list(long_hold), y=[i for i in range(len(long_hold))], s=10, marker='d', edgecolors="red", zorder=2, color='white') # zorder設定該點覆寫線 # 畫線兩端標注圖 for x, y, label in zip(list(short_hold), range(len(short_hold)), short_hold.index): plt.text(x=x, y=y, s=label+'({}) '.format(abs(x)), horizontalalignment='right', verticalalignment='center', fontsize=10) for x, y, label in zip(list(long_hold), range(len(long_hold)), long_hold.index): plt.text(x=x, y=y, s=' '+label+'({})'.format(abs(x)), horizontalalignment='left', verticalalignment='center', fontsize=10) # 設定排名 size = [17, 16, 15] + [8 for i in range(max(len(short_hold), len(long_hold))-3)] color = ['#b91818', '#e26012', '#dd9f10'] + ['#404040' for i in range(max(len(short_hold), len(long_hold))-3)] for i, s, c in zip(range(max(len(short_hold), len(long_hold))+1), size, color): plt.annotate(s=i+1, xy=(0, i), fontsize=s, ma='center', ha='center', color=c) # 坐標軸y反置 ax.invert_yaxis() # 坐標軸不可見 ax.set_xticks([]) ax.set_yticks([]) ax.spines['top'].set_visible(False) # 去上邊框 ax.spines['bottom'].set_visible(False) # 去下邊框 ax.spines['left'].set_visible(False) # 去左邊框 ax.spines['right'].set_visible(False) # 去右邊框 # 設定title ax.set_title('黃金持倉龍虎榜單({})'.format(date), position=(0.7, 1.07), fontdict=dict(fontsize=20, color='black')) # 自動獲取ax圖例句柄及其標簽 handles, labels = ax.get_legend_handles_labels() plt.legend(handles=handles, ncol=2, bbox_to_anchor=(0.75, 1.05), labels=labels, edgecolor='white', fontsize=10) # 保存fig image_filename = "lollipop_rank.png" plt.savefig(image_filename) encoded_image = base64.b64encode(open(image_filename, 'rb').read()) # plt.show() return encoded_image
PS:如有需要Python學習資料的小伙伴可以加下方的群去找免費管理員領取
可以免費領取原始碼、專案實戰視頻、PDF檔案等
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/10159.html
標籤:Python
上一篇:網路爬蟲:利用selenium,pyquery庫抓取并處理京東上的圖片并存盤到使用mongdb資料庫進行存盤
下一篇:11_IO多路復用
