【Python Onramp】7. web端可视化:北京地铁数据统计分析实例以及简易Echarts绘图
系列文章目錄
見【Python Onramp】 0. 卷首語
上一篇:【Python Onramp】6.一篇文章了解web開發要點:用Python開發簡易的網頁端成績查詢系統
下一篇:【Python Onramp】8.Python爬蟲(1)基于requests和BeautifulSoup的全國區劃數據爬蟲
本文目錄
- 系列文章目錄
- 開篇總結
- 項目描述
- task1
- task2
- task3
- task4
- 要點總覽
- 要點1:Echarts
- 要點2:時間函數
- 要點3:pandas.dataframe復習
- 要點4:JavaScript數據結構:JSON
- 具體實現
- step1:統計
- 時間提取
- 時間軸統計
- step2:利用jsonify傳遞
- step3:直接保存為js數據實現
開篇總結
一個思想:查找資料!將關鍵詞百度一下,比如你想得到Echarts的模板,就可以直接百度。由于編程學習內容非常多樣,查找不僅是方法,更是技能
幾個要點:
- Echarts
- 時間datetime模塊
- JSON
- pandas.dataframe的一些知識復習
項目描述
詳見:https://github.com/Honour-Van/CS50/tree/master/Visualization2
這個項目中你將通過北京地鐵數據的展示進行
對地鐵數據進行分析之后的可視化分析。
數據見 data,數據是北京地鐵刷卡數據。第一行是數據標題,其含義如下:
- a) carType:SUB 是唯一取值,表明數據是地鐵,本次作業可以不用;
- b)icID:交通卡編號,每個編號對應一張卡,已經消密脫敏;
- c) cardType:卡類型
- d) tradeType:交易類型
- e)UpLine:上車線路編號
- f) UpTime:上車時間
- g) UpStation:上車站編號
- h) DownLine:下車線路編號
- i)DownTime:下車時間
- j) DownStation:下車站編號
- k) State:棄用
壓縮包內的 PDF 文檔是地鐵線路編號和車站編號,供參考。
為便于程序調試,數據中有 Subway_20190301_top100000.txt(實際上是 Subway_20180301_top100000.txt,誤為 2019),是 Subway_20180301.txt 的前 100000 行數據,可以用于初步調試程序,待調試完畢后再用完整數據跑,節省時間
task1
計算乘車耗時時段內的人數。每條記錄是一次乘車行為,下車時間減去上車時間,即為耗時,題目要求統計耗時 10 分鐘有多少人,耗時 15 分鐘有多少人。以分鐘為單位,計算出每個時間段內的人數。如 1 分鐘:10 人,2 分鐘 20 人,……,10 分鐘 500 人,30 分鐘 5000 人。計算耗時,用 round()函數四舍五入到分中。對下車時間早于或等于上車時間的數據予以清除,對超過 120 分鐘的數據予以清除,對于不是 20180301 的數據清除。輸出時,按耗時升序排序輸出到 PeopleInSubwayTime.txt,并在 Excel 中打開該文件,形成條形圖。
task2
所有地鐵內人數時間分布。以 10 分鐘為間隔,統計地鐵內人數多少。進站相當于人數增加,出站相當于人數減少。以凌晨 00:00 開始計數,此刻人數為 0。統計 00:00-00:09,00:10-00:19,以此類推,要求標記為:00:00-00:00,00:10-00:19(以下同)。清除數據的規則與 5 相同。按時間自然升序輸出到 PeopleInSubwayCount.txt,形成折線圖;
task3
利用兩個數據文件,通過 Python+Flask 模式,將數據輸出到網頁,利用 eCharts 顯示出形如 Excel 的統計圖。每個統計圖都支持柱狀圖和折線圖切換;
task4
利用兩個數據文件,通過包含 JS 數據文件方式,顯示出形如 Excel 的統計圖。與 task3 頁面要求一致,僅數據源不同而已。
要點總覽
主要的內容包括Flask和JavaScript我們在之前都已經學過了,如果你已經掌握了,那么這個項目將會是一個非常愉悅的項目。
要點1:Echarts
Echarts是一個基于 JavaScript 的開源可視化圖表庫,版式精美簡約,具有可交互性。
之前我們已經使用過其Python版Pyecharts,但實際上,PyEcharts只是Echarts的一個封裝,自動生成對應的JavaScript代碼。我們現在直接動手編輯HTML和JavaScript。
在網頁端,可以直接利用圖形界面生成所需的options對象,在實際操作時,只需選取指定對象進行options設置即可。
要點2:時間函數
datetime 的使用方法:
- strptime()函數:將datetime對象轉換為指定時間格式的字符串
- timedelta類型:用于求時間差
我們每十分鐘一分組,還需要使用如下兩個函數,分別為時間編組和對應組別時間的格式化輸出。
def time_group(etime: datetime.time) -> int:return etime.hour * 6 + (etime.minute // 10)def group2time(group_num: int) -> str:hour = group_num // 6dec_min = group_num % 6return str(hour).rjust(2, '0') + ":" + str(dec_min * 10).rjust(2, '0') + '-' + str(hour).rjust(2, '0') + ":" + str(dec_min * 10 + 9).rjust(2, '0')要點3:pandas.dataframe復習
導出行列數以表示進度:https://blog.csdn.net/lwgkzl/article/details/80988126
dataframe 更名:https://blog.csdn.net/weixin_43745169/article/details/89306686
dataframe 定位:https://blog.csdn.net/W_weiying/article/details/81411257
另外,不會把 python 列表直接變成 js 中的變量,從而使用了復制粘貼。
要點4:JavaScript數據結構:JSON
https://www.runoob.com/json/json-tutorial.html
JSON是JavaScript的內置數據結構,也通用于各種編程語言中,在flask端的數據傳遞過程中,我們可以利用jsonify函數將dataframe編碼為JSON,隨后傳到網頁端進行顯示。這樣的程序,數據不在網頁端顯示,保密等級上升一層。
詳細可以自行搜索用法。
具體實現
step1:統計
時間提取
不正則數據:
- 下車早于上車
- 消除不在當日的數據
- 清除前后超過 120 分鐘的數據
返回上車和下車時間即可,上述的工作可以交由具體實現時。
第二次決定加入時間差作為第三個返回值
from datetime import datetime, time import pandas as pd from mytool import progress_bar, time_group, group2time# filename = "test/test.txt" # filename = "data/Subway_20190301_Top100000.txt" filename = "data/Subway_20180301.txt"df = pd.read_csv(filename) res = {}pb = progress_bar(df.shape[0], 100)for _, line in df.iterrows():starttime = datetime.strptime(str(line["UpTime"]), "%Y%m%d%H%M%S")endtime = datetime.strptime(str(line["DownTime"]), "%Y%m%d%H%M%S")if starttime.day != 1 or endtime.day != 1:continuedelta = endtime - starttimeif delta.days < 0:continueif delta.seconds > 7200:continuetg = time_group(starttime)res[tg] = res.get(tg, 0) + 1tg = time_group(endtime)res[tg] = res.get(tg, 0) - 1pb.progress(_)for i in range(143):res[i+1] = res.get(i+1, 0) + res.get(i, 0)res = sorted(res.items(), key=lambda x: x[0]) res = [(group2time(x[0]),x[1]) for x in res] pd.DataFrame(res, columns=['時間組', '人數']).to_csv("./out/PeopleInSubwayCount.csv",index=False)其中,mytool是自己實現的幾個組件,包括時間處理以及進度條組件:
from datetime import datetimeclass progress_bar():def __init__(self, workload, length) -> None:self._workload = workloadself.stage_d = int(workload/length)self.stage_c = 0self.stage_n = 0self.length = lengthdef progress(self, cur):if cur > self.stage_c:self.stage_c += self.stage_dself.stage_n += 1print('\r' + "[" + (self.stage_n *'o').ljust(self.length) + "]" + "loading...", end='')def time_group(etime: datetime.time) -> int:return etime.hour * 6 + (etime.minute // 10)def group2time(group_num: int) -> str:hour = group_num // 6dec_min = group_num % 6return str(hour).rjust(2, '0') + ":" + str(dec_min * 10).rjust(2, '0') + '-' + str(hour).rjust(2, '0') + ":" + str(dec_min * 10 + 9).rjust(2, '0')時間軸統計
如果記錄的進入離開時間在特定范圍內,記增減。注意,每次要做部分和,保證當前是之前所有進站出站數據的綜合結果。
from datetime import datetime import pandas as pd from mytool import progress_bar# filename = "data/Subway_20190301_top100000.txt" filename = "data/Subway_20180301.txt" res = {} df = pd.read_csv(filename)pb = progress_bar(df.shape[0], 100)for _, line in df.iterrows():starttime = datetime.strptime(str(line["UpTime"]), "%Y%m%d%H%M%S")endtime = datetime.strptime(str(line["DownTime"]), "%Y%m%d%H%M%S")if starttime.day != 1 or endtime.day != 1:continuedelta = endtime - starttimeif delta.days < 0:continueif delta.seconds > 7200:continueminutes = round(delta.seconds / 60)res[minutes] = res.get(minutes, 0) + 1pb.progress(_)res = sorted(res.items(), key=lambda x: x[0]) pd.DataFrame(res, columns=['耗時(分鐘)', '人數']).to_csv("./out/PeopleInSubwayTime.csv", index=False)step2:利用jsonify傳遞
from flask import Flask, jsonify # 新增代碼。裝入Flask import pandas as pdapp = Flask(__name__) # 新增代碼@app.route("/") # 新增代碼,對應執行root()函數 def root():return app.send_static_file("visual.html")@app.route("/getData1") def getData1():df = pd.read_csv("./out/PeopleInSubwayTime.csv")data = [df.iloc[:, 0].tolist(), df.iloc[:, 1].tolist()]print(data)return jsonify(data)@app.route("/getData2") def getData2():df = pd.read_csv("./out/PeopleInSubwayCount.csv")data = [df.iloc[:, 0].tolist(), df.iloc[:, 1].tolist()]print(data)return jsonify(data)if __name__ == "__main__":app.run(host="0.0.0.0", port=80, debug=True) # eof <!DOCTYPE html> <html><head><meta charset="utf-8" /><title>ECharts</title><script src="/static/echarts.min.js"></script><script src="/static/jquery-3.6.0.min.js"></script><!--引入自定義的數據--></head><body><div id="stat1" style="width: 600px; height: 400px"></div><div id="stat2" style="width: 600px; height: 400px"></div><!--統計圖顯示于此--><script type="text/javascript">var EChart1 = echarts.init(document.getElementById("stat1"));var EChart2 = echarts.init(document.getElementById("stat2"));var option = {title: { text: "" },tooltip: {},legend: { data: ["折線圖", "柱形圖"] },toolbox: {feature: {magicType: { type: ["line", "bar"] },saveAsImage: {},},},xAxis: { data: [] },yAxis: {},series: [{ name: "折線圖", type: "line", data: [] },{ name: "柱形圖", type: "bar", data: [] },],}; /*設置統計圖形參數*/$.get("/getData1", function (data) {option.title.text = "地鐵乘車用時統計";option.xAxis.data = data[0];option.series[0].data = eval("[" + data[1] + "]");option.series[1].data = eval("[" + data[1] + "]");EChart1.setOption(option);});$.get("/getData2", function (data) {option.title.text = "地鐵站內人員統計";option.xAxis.data = data[0];option.series[0].data = eval("[" + data[1] + "]");option.series[1].data = eval("[" + data[1] + "]");EChart2.setOption(option);});</script></body> </html>step3:直接保存為js數據實現
這樣的話,flask端需要做的工作就很少了
from flask import Flask, jsonify # 新增代碼。裝入Flask import pandas as pdapp = Flask(__name__) # 新增代碼@app.route("/") # 新增代碼,對應執行root()函數 def root():return app.send_static_file("visjs.html")if __name__ == "__main__":app.run(host="0.0.0.0", port=80, debug=True) # eofjs端需要稍微多加一點數據重組的操作:
<!DOCTYPE html> <html><head><meta charset="utf-8" /><title>ECharts</title><script src="./static/echarts.min.js"></script><script src="./static/myData.js"></script></head><body><div id="stat1" style="width: 600px; height: 400px"></div><div id="stat2" style="width: 600px; height: 400px"></div><!--統計圖顯示于此--><script type="text/javascript">var EChart1 = echarts.init(document.getElementById("stat1"));var EChart2 = echarts.init(document.getElementById("stat2"));var option = {title: { text: "" },tooltip: {},legend: { data: ["折線圖", "柱形圖"] },toolbox: {feature: {magicType: { type: ["line", "bar"] },saveAsImage: {},},},xAxis: { data: [] },yAxis: {},series: [{ name: "折線圖", type: "line", data: [] },{ name: "柱形圖", type: "bar", data: [] },],}; /*設置統計圖形參數*/option.title.text = "地鐵乘車用時統計";option.xAxis.data = userData1[0];option.series[0].data = userData1[1];option.series[1].data = userData1[1];EChart1.setOption(option);option.title.text = "地鐵站內人員統計";option.xAxis.data = userData2[0];option.series[0].data = userData2[1];option.series[1].data = userData2[1];EChart2.setOption(option);</script></body> </html>總結
以上是生活随笔為你收集整理的【Python Onramp】7. web端可视化:北京地铁数据统计分析实例以及简易Echarts绘图的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: JavaScript制作网页动画
- 下一篇: 初学者:英语和数学不好,能学编程吗?