【Python Onramp】7. web端可视化:北京地铁数据统计分析实例以及简易Echarts绘图
系列文章目錄
見【Python Onramp】 0. 卷首語(yǔ)
上一篇:【Python Onramp】6.一篇文章了解web開發(fā)要點(diǎn):用Python開發(fā)簡(jiǎn)易的網(wǎng)頁(yè)端成績(jī)查詢系統(tǒng)
下一篇:【Python Onramp】8.Python爬蟲(1)基于requests和BeautifulSoup的全國(guó)區(qū)劃數(shù)據(jù)爬蟲
本文目錄
- 系列文章目錄
- 開篇總結(jié)
- 項(xiàng)目描述
- task1
- task2
- task3
- task4
- 要點(diǎn)總覽
- 要點(diǎn)1:Echarts
- 要點(diǎn)2:時(shí)間函數(shù)
- 要點(diǎn)3:pandas.dataframe復(fù)習(xí)
- 要點(diǎn)4:JavaScript數(shù)據(jù)結(jié)構(gòu):JSON
- 具體實(shí)現(xiàn)
- step1:統(tǒng)計(jì)
- 時(shí)間提取
- 時(shí)間軸統(tǒng)計(jì)
- step2:利用jsonify傳遞
- step3:直接保存為js數(shù)據(jù)實(shí)現(xiàn)
開篇總結(jié)
一個(gè)思想:查找資料!將關(guān)鍵詞百度一下,比如你想得到Echarts的模板,就可以直接百度。由于編程學(xué)習(xí)內(nèi)容非常多樣,查找不僅是方法,更是技能
幾個(gè)要點(diǎn):
- Echarts
- 時(shí)間datetime模塊
- JSON
- pandas.dataframe的一些知識(shí)復(fù)習(xí)
項(xiàng)目描述
詳見:https://github.com/Honour-Van/CS50/tree/master/Visualization2
這個(gè)項(xiàng)目中你將通過北京地鐵數(shù)據(jù)的展示進(jìn)行
對(duì)地鐵數(shù)據(jù)進(jìn)行分析之后的可視化分析。
數(shù)據(jù)見 data,數(shù)據(jù)是北京地鐵刷卡數(shù)據(jù)。第一行是數(shù)據(jù)標(biāo)題,其含義如下:
- a) carType:SUB 是唯一取值,表明數(shù)據(jù)是地鐵,本次作業(yè)可以不用;
- b)icID:交通卡編號(hào),每個(gè)編號(hào)對(duì)應(yīng)一張卡,已經(jīng)消密脫敏;
- c) cardType:卡類型
- d) tradeType:交易類型
- e)UpLine:上車線路編號(hào)
- f) UpTime:上車時(shí)間
- g) UpStation:上車站編號(hào)
- h) DownLine:下車線路編號(hào)
- i)DownTime:下車時(shí)間
- j) DownStation:下車站編號(hào)
- k) State:棄用
壓縮包內(nèi)的 PDF 文檔是地鐵線路編號(hào)和車站編號(hào),供參考。
為便于程序調(diào)試,數(shù)據(jù)中有 Subway_20190301_top100000.txt(實(shí)際上是 Subway_20180301_top100000.txt,誤為 2019),是 Subway_20180301.txt 的前 100000 行數(shù)據(jù),可以用于初步調(diào)試程序,待調(diào)試完畢后再用完整數(shù)據(jù)跑,節(jié)省時(shí)間
task1
計(jì)算乘車耗時(shí)時(shí)段內(nèi)的人數(shù)。每條記錄是一次乘車行為,下車時(shí)間減去上車時(shí)間,即為耗時(shí),題目要求統(tǒng)計(jì)耗時(shí) 10 分鐘有多少人,耗時(shí) 15 分鐘有多少人。以分鐘為單位,計(jì)算出每個(gè)時(shí)間段內(nèi)的人數(shù)。如 1 分鐘:10 人,2 分鐘 20 人,……,10 分鐘 500 人,30 分鐘 5000 人。計(jì)算耗時(shí),用 round()函數(shù)四舍五入到分中。對(duì)下車時(shí)間早于或等于上車時(shí)間的數(shù)據(jù)予以清除,對(duì)超過 120 分鐘的數(shù)據(jù)予以清除,對(duì)于不是 20180301 的數(shù)據(jù)清除。輸出時(shí),按耗時(shí)升序排序輸出到 PeopleInSubwayTime.txt,并在 Excel 中打開該文件,形成條形圖。
task2
所有地鐵內(nèi)人數(shù)時(shí)間分布。以 10 分鐘為間隔,統(tǒng)計(jì)地鐵內(nèi)人數(shù)多少。進(jìn)站相當(dāng)于人數(shù)增加,出站相當(dāng)于人數(shù)減少。以凌晨 00:00 開始計(jì)數(shù),此刻人數(shù)為 0。統(tǒng)計(jì) 00:00-00:09,00:10-00:19,以此類推,要求標(biāo)記為:00:00-00:00,00:10-00:19(以下同)。清除數(shù)據(jù)的規(guī)則與 5 相同。按時(shí)間自然升序輸出到 PeopleInSubwayCount.txt,形成折線圖;
task3
利用兩個(gè)數(shù)據(jù)文件,通過 Python+Flask 模式,將數(shù)據(jù)輸出到網(wǎng)頁(yè),利用 eCharts 顯示出形如 Excel 的統(tǒng)計(jì)圖。每個(gè)統(tǒng)計(jì)圖都支持柱狀圖和折線圖切換;
task4
利用兩個(gè)數(shù)據(jù)文件,通過包含 JS 數(shù)據(jù)文件方式,顯示出形如 Excel 的統(tǒng)計(jì)圖。與 task3 頁(yè)面要求一致,僅數(shù)據(jù)源不同而已。
要點(diǎn)總覽
主要的內(nèi)容包括Flask和JavaScript我們?cè)谥岸家呀?jīng)學(xué)過了,如果你已經(jīng)掌握了,那么這個(gè)項(xiàng)目將會(huì)是一個(gè)非常愉悅的項(xiàng)目。
要點(diǎn)1:Echarts
Echarts是一個(gè)基于 JavaScript 的開源可視化圖表庫(kù),版式精美簡(jiǎn)約,具有可交互性。
之前我們已經(jīng)使用過其Python版Pyecharts,但實(shí)際上,PyEcharts只是Echarts的一個(gè)封裝,自動(dòng)生成對(duì)應(yīng)的JavaScript代碼。我們現(xiàn)在直接動(dòng)手編輯HTML和JavaScript。
在網(wǎng)頁(yè)端,可以直接利用圖形界面生成所需的options對(duì)象,在實(shí)際操作時(shí),只需選取指定對(duì)象進(jìn)行options設(shè)置即可。
要點(diǎn)2:時(shí)間函數(shù)
datetime 的使用方法:
- strptime()函數(shù):將datetime對(duì)象轉(zhuǎn)換為指定時(shí)間格式的字符串
- timedelta類型:用于求時(shí)間差
我們每十分鐘一分組,還需要使用如下兩個(gè)函數(shù),分別為時(shí)間編組和對(duì)應(yīng)組別時(shí)間的格式化輸出。
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')要點(diǎn)3:pandas.dataframe復(fù)習(xí)
導(dǎo)出行列數(shù)以表示進(jìn)度: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
另外,不會(huì)把 python 列表直接變成 js 中的變量,從而使用了復(fù)制粘貼。
要點(diǎn)4:JavaScript數(shù)據(jù)結(jié)構(gòu):JSON
https://www.runoob.com/json/json-tutorial.html
JSON是JavaScript的內(nèi)置數(shù)據(jù)結(jié)構(gòu),也通用于各種編程語(yǔ)言中,在flask端的數(shù)據(jù)傳遞過程中,我們可以利用jsonify函數(shù)將dataframe編碼為JSON,隨后傳到網(wǎng)頁(yè)端進(jìn)行顯示。這樣的程序,數(shù)據(jù)不在網(wǎng)頁(yè)端顯示,保密等級(jí)上升一層。
詳細(xì)可以自行搜索用法。
具體實(shí)現(xiàn)
step1:統(tǒng)計(jì)
時(shí)間提取
不正則數(shù)據(jù):
- 下車早于上車
- 消除不在當(dāng)日的數(shù)據(jù)
- 清除前后超過 120 分鐘的數(shù)據(jù)
返回上車和下車時(shí)間即可,上述的工作可以交由具體實(shí)現(xiàn)時(shí)。
第二次決定加入時(shí)間差作為第三個(gè)返回值
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=['時(shí)間組', '人數(shù)']).to_csv("./out/PeopleInSubwayCount.csv",index=False)其中,mytool是自己實(shí)現(xiàn)的幾個(gè)組件,包括時(shí)間處理以及進(jìn)度條組件:
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')時(shí)間軸統(tǒng)計(jì)
如果記錄的進(jìn)入離開時(shí)間在特定范圍內(nèi),記增減。注意,每次要做部分和,保證當(dāng)前是之前所有進(jìn)站出站數(shù)據(jù)的綜合結(jié)果。
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=['耗時(shí)(分鐘)', '人數(shù)']).to_csv("./out/PeopleInSubwayTime.csv", index=False)step2:利用jsonify傳遞
from flask import Flask, jsonify # 新增代碼。裝入Flask import pandas as pdapp = Flask(__name__) # 新增代碼@app.route("/") # 新增代碼,對(duì)應(yīng)執(zhí)行root()函數(shù) 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><!--引入自定義的數(shù)據(jù)--></head><body><div id="stat1" style="width: 600px; height: 400px"></div><div id="stat2" style="width: 600px; height: 400px"></div><!--統(tǒng)計(jì)圖顯示于此--><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: [] },],}; /*設(shè)置統(tǒng)計(jì)圖形參數(shù)*/$.get("/getData1", function (data) {option.title.text = "地鐵乘車用時(shí)統(tǒng)計(jì)";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 = "地鐵站內(nèi)人員統(tǒng)計(jì)";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數(shù)據(jù)實(shí)現(xiàn)
這樣的話,flask端需要做的工作就很少了
from flask import Flask, jsonify # 新增代碼。裝入Flask import pandas as pdapp = Flask(__name__) # 新增代碼@app.route("/") # 新增代碼,對(duì)應(yīng)執(zhí)行root()函數(shù) def root():return app.send_static_file("visjs.html")if __name__ == "__main__":app.run(host="0.0.0.0", port=80, debug=True) # eofjs端需要稍微多加一點(diǎn)數(shù)據(jù)重組的操作:
<!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><!--統(tǒng)計(jì)圖顯示于此--><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: [] },],}; /*設(shè)置統(tǒng)計(jì)圖形參數(shù)*/option.title.text = "地鐵乘車用時(shí)統(tǒng)計(jì)";option.xAxis.data = userData1[0];option.series[0].data = userData1[1];option.series[1].data = userData1[1];EChart1.setOption(option);option.title.text = "地鐵站內(nèi)人員統(tǒng)計(jì)";option.xAxis.data = userData2[0];option.series[0].data = userData2[1];option.series[1].data = userData2[1];EChart2.setOption(option);</script></body> </html>總結(jié)
以上是生活随笔為你收集整理的【Python Onramp】7. web端可视化:北京地铁数据统计分析实例以及简易Echarts绘图的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: JavaScript制作网页动画
- 下一篇: python英语查询词典-随堂作业