引言:
用 Python 做可视化大屏不用复杂框架!这篇教程以2021 年气象监测数据(风速、波高、气温等)为案例,教你用 Flask 快速搭建 Web 可视化大屏 —— 代码简约如 app.py,步骤详细到小白能上手,功能实用到同行会点赞,核心干货直接复制就能跑通~
目录
引言:
工具准备
安装环境
核心结构
核心代码
程序运行
完整资源
总结:用 Flask 搭大屏,简约而不简单
工具准备
| 类别 | 具体内容 | 作用说明 |
|---|---|---|
| 基础环境 | Python 3.8+(推荐 3.9) | 兼容性最优,避免低版本缺少 Flask 新特性,高版本可能有依赖冲突 |
| 代码编辑器 | PyCharm(社区版即可)/ VS Code | PyCharm 自带 Flask 插件,新手调试更方便;VS Code 轻量,配插件也能快速开发 |
| 核心 Python 库 | Flask(Web 框架)、pandas(数据处理)、openpyxl(读取 Excel) | Flask 负责搭 Web 服务,pandas 处理气象数据,openpyxl 解决 Excel 读取报错问题 |
| 可视化工具 | ECharts 5.x(无需安装,CDN 引入) | 生成柱状图、折线图、散点图等,比 matplotlib 更适合 Web 端交互 |
| 数据文件 | 20212.xlsx(气象数据,含风速、有效波高、气温等 16 个指标) | 实战数据源,需提前放到指定文件夹,避免路径 错误 |
安装环境
# openpyxl用于读取Excel
pip install flask pandas openpyxl -i https://pypi.tuna.tsinghua.edu.cn/simple/
核心结构
Flask_Ocean_Dashboard/ # 项目根目录
├─ app.py # 核心Web服务(路由+调用图表逻辑)
├─ chart.py # 图表业务逻辑(m1-m6函数,处理数据+生成图表)
├─ data/ # 数据文件夹(统一管理数据源)
│ └─ 20212.xlsx # 气象原始数据
├─ static/ # 静态资源文件夹(Flask默认规范,放JS/CSS/图片)
│ ├─ js/ # JS文件(图表库、交互逻辑)
│ │ ├─ jquery.js # 简化DOM操作(如加载动画控制)
│ │ ├─ echarts.min.js# ECharts核心库
│ │ └─ js.js # 自定义图表逻辑(可选)
│ ├─ css/ # 样式文件
│ │ └─ comon0.css # 通用样式(如头部标题样式)
│ └─ images/ # 图片资源
│ └─ loading.gif # 页面加载动画图片
└─ templates/ # 模板文件夹(Flask默认规范,放HTML页面)
├─ index.html # 大屏主页面(整合所有图表)
├─ bar2.html # 柱状图页面(被index.html引入)
├─ line.html # 折线图页面(温度最大值趋势)
├─ bar3.html # 另一类柱状图页面
├─ scatter.html # 散点图页面
├─ line2.html # 第二类折线图页面
└─ pie.html # 饼图页面(五个指标平均值)
👉 简约设计思路:无多余文件,核心功能集中,维护成本低
核心代码
1. app.py:Flask 主程序(简约到极致)
from flask import Flask, render_template from chart import m1, m2, m4, m3, m5, m6 初始化Flask应用:__name__表示“以当前文件为核心,自动找static/templates” app = Flask(__name__) 核心路由:浏览器访问“http://IP:端口/”时触发的逻辑 @app.route('/') def hello_world(): # put application's code here m1() # 对应bar2.html的图表数据(比如某类气象指标柱状图) m2() # 对应line.html的“2021年不同月份各温度最大值”折线图 m3() # 对应bar3.html的图表数据 m4() # 对应scatter.html的散点图数据(比如风速与波高的关系) m5() # 对应line2.html的折线图数据 m6() # 对应pie.html的“五个平均值饼图”数据 return render_template("index.html") if __name__ == '__main__': app.run(debug=True, host='0.0.0.0', port=5000) # port=5000是默认端口图表逻辑模块化:
将
m1~m6共 6 个图表的生成逻辑(含数据处理、图表配置)封装在chart.py中,app.py仅通过from chart import...导入调用,不掺杂任何图表细节代码。避免app.py代码冗余(若将所有图表逻辑写在 app.py,会导致文件臃肿难维护);
后续新增图表(如 m7)、修改图表样式(如改折线图为柱状图),只需在chart.py中调整对应函数,无需动app.py的路由逻辑,符合 “单一职责” 原则,团队协作或后续迭代时效率更高。渲染流程极简:
仅 1 个核心路由/,逻辑仅 2 步:
①调用m1~m6生成图表资源(如图表图片、ECharts 配置);
②渲染index.html返回页面,无复杂中间件、无多余分支判断
完整流程 “浏览器请求→Flask 调用图表函数→返回可视化页面” 一目了然,新手能快速对应代码与实际效果;
无冗余逻辑,符合 Flask “微框架” 的轻量特性,避免过度设计,开发效率高。
2.index.html:可视化大屏页面
<!-- 华丽转身的程序喵 https://m.tb.cn/h.SxeNlci?tk=ubC5fNmxP5x --> <!doctype html> <html> <head> <meta charset="utf-8"> <title>index</title> <!-- 1. 引入静态资源:按“JS→CSS→自定义样式”顺序,避免加载冲突 --> <script type="text/javascript" src="../static/js/jquery.js"></script> <!-- 简化DOM操作 --> <link rel="stylesheet" href="../static/css/comon0.css"> <!-- 通用样式(如头部标题) --> <style type="text/css"> /* 自定义布局:解决多图表排版问题,小白可直接复制 */ *{ margin: 0; padding: 0; }/* 清除默认边距,避免布局错乱 */ .main{ width: 100%; height: 100%; position: absolute; } .quarter-div{ height: 40%; float: left; } .blue{ } .green{ } .orange{ } .red{ } </style> </head> <body> <!-- 加载动画:提升体验,避免用户等半天以为卡了 --> <div class="loading"> <div class="loadbox"> <img src="../static/images/loading.gif"> 页面加载中... </div> </div> <头部:标题+实时时间(用户一眼知道大屏主题和当前时间) --> <div class="head"> <h1>海洋数据可视化大屏</h1> <div class="time" id="showTime">2019年12月05日16时16分54秒</div> </div> <!-- 上半区图表:用quarter-div容器,include引入单独图表页面 --> <div class="main"> <!-- 第一个图表:bar2.html(柱状图) --> <div class="quarter-div green;width: 400px;" > <h2>2021年各月风速最大值</h2> {% include "bar2.html" %} <!-- 引入图表页面:模块化核心,改bar2不用动index --> </div> </div> <!-- 第二个图表:line.html(温度最大值折线图) --> <div class="quarter-div red;width: 420px;" > <h2>2021年不同月份各温度最大值</h2> {% include "line.html" %} </div> <div class="quarter-div orange;width: 650px;" > <h2></h2> {% include "bar3.html" %} </div> </div> <div class="main2" style="width: 100%;height: 500px;position: absolute;margin-top: 420px"> <div style="float: left;width: 37%;height: 100%"> {% include "scatter.html" %} </div> <div style="float: left;width: 37%;height: 100%"> {% include "line2.html" %} </div> <div style="float: left;width: 26%;height: 100%"> <h2>五个平均值饼图</h2> {% include "pie.html" %} </div> </div> <!--实时时间JS:可直接复制,无需搞懂原理 --> <script> var t = null; t = setTimeout(time, 1000);//開始运行 function time() { clearTimeout(t);//清除定时器 dt = new Date(); var y = dt.getFullYear(); var mt = dt.getMonth() + 1; var day = dt.getDate(); var h = dt.getHours();//获取时 var m = dt.getMinutes();//获取分 var s = dt.getSeconds();//获取秒 var t = null; document.getElementById("showTime").innerHTML = y + "年" + Appendzero(mt) + "月" + Appendzero(day) + "日" + Appendzero(h) + "时" + Appendzero(m) + "分" + Appendzero(s) + "秒"; function Appendzero(obj) { if (obj < 10) return "0" + "" + obj; else return obj; } t = setTimeout(time, 1000); //设定定时器,循环运行 } </script> </div> <script> $(document).ready(function () { var arr = []; var max; $(".paim li i").each(function () { arr.push($(this).text()); }) //alert(arr) max = Math.max.apply(null, arr); $(".paim .pmbar span").each(function () { var i = $(this).parents("li").index() w = arr[i] / max * 100; sw = w.toFixed(0) + '%' $(this).css({ width: sw }) }) }) </script> <!-- 引入图表核心JS:ECharts库+自定义图表逻辑 --> <script type="text/javascript" src="../static/js/echarts.min.js"></script> <script language="JavaScript" src="../static/js/js.js"></script> </body> </html>{% include %} 模块化:
比如 line.html 是 “月份温度最大值折线图”,想改这个图表的样式,直接改 templates/line.html 就行,不用在几百行的 index.html 里找代码 —— 这种 “页面拆分” 能大幅降低维护成本;
实时时间组件:几行 JS 实现时间自动更新,大屏显示实时时间更专业,直接复制就能用;
加载动画:很多新手忽略这个细节,大屏加载图表需要时间(尤其数据多的时候),loading.gif 能让用户知道 “正在加载,不是卡了”,提升体验;
CSS 布局容错:用 float 和 position 避免图表重叠,复制这段样式也能保证大屏在不同浏览器里排版正常。
3.chart.py 逻辑:数据处理核心
# chart.py:每个m函数对应一个图表的数据处理+ECharts配置生成 import pandas as pd from pyecharts.charts import Bar, Line, Pie, Scatter from pyecharts import options as opts # 图表样式配置 from pyecharts.globals import ThemeType # 图表主题 # 先写一个通用数据加载函数:处理Excel异常值,避免重复代码(同行认可的复用思路) def load_data(): # 读取Excel数据(需指定sheet_name,openpyxl为引擎) df = pd.read_excel('data/20212.xlsx', sheet_name='Sheet1', engine='openpyxl') # 处理异常值:Excel中99/999是无效值,替换为NaN后删除 df = df.replace([99, 999], pd.NA).dropna(subset=['风速', '有效波高', '气温', '水温', '大气压力']) # 提取月份(用于line.html的“不同月份温度最大值”) df['月份'] = df['月'].astype(str).str.zfill(2) # 补0:1→01 return df # m2():对应line.html的“2021年不同月份各温度最大值”折线图 def m2(): df = load_data() # 计算每个月份的气温最大值(核心业务逻辑) month_temp_max = df.groupby('月份')['气温'].max().reset_index() # 生成折线图,保存到templates/line.html(让index.html能include) line_chart = ( Line(init_opts=opts.InitOpts(theme=ThemeType.LIGHT, width="100%", height="90%")) .add_xaxis(month_temp_max['月份'].tolist()) # X轴:月份 .add_yaxis("气温最大值(℃)", month_temp_max['气温'].tolist(), is_smooth=True) # Y轴:温度 .set_global_opts( title_opts=opts.TitleOpts(title="2021年不同月份各温度最大值"), # 图表标题 xaxis_opts=opts.AxisOpts(name="月份"), # X轴名称 yaxis_opts=opts.AxisOpts(name="气温(℃)") # Y轴名称 ) ) # 保存图表到templates文件夹(必须和index.html同目录,include才能找到) line_chart.render("templates/line.html") # m6():对应pie.html的“五个平均值饼图”(风速、气温、水温、有效波高、大气压力) def m6(): df = load_data() # 计算五个指标的平均值(保留2位小数) avg_wind = round(df['风速'].mean(), 2) avg_temp = round(df['气温'].mean(), 2) avg_water_temp = round(df['水温'].mean(), 2) avg_wave = round(df['有效波高'].mean(), 2) avg_pressure = round(df['大气压力'].mean(), 2) # 生成饼图 pie_chart = ( Pie(init_opts=opts.InitOpts(theme=ThemeType.LIGHT, width="100%", height="90%")) .add( "指标平均值", [ ("风速(m/s)", avg_wind), ("气温(℃)", avg_temp), ("水温(℃)", avg_water_temp), ("有效波高(m)", avg_wave), ("大气压力(hPa)", avg_pressure) ], radius=["40%", "75%"] # 环形饼图,更美观 ) .set_global_opts(title_opts=opts.TitleOpts(title="五个气象指标平均值")) .set_series_opts(label_opts=opts.LabelOpts(formatter="{b}: {c}")) # 显示指标名+数值 ) pie_chart.render("templates/pie.html") # 其他m1/m3/m4/m5函数逻辑类似:m1对应bar2.html,m3对应bar3.html,m4对应scatter.html,m5对应line2.html # 可以参考m2/m6的逻辑,替换指标(如风速→有效波高)、图表类型(Line→Bar)即可 #华丽转身的程序喵 #https://m.tb.cn/h.SxeNlci?tk=ubC5fNmxP5x通用数据加载函数:
load_data () 处理 Excel 读取和异常值,m1-m6 都调用它,避免重复代码(如果每个函数都写一次读 Excel,改路径要改 6 次);
pyecharts 生成 HTML:直接把图表渲染成 HTML 文件,index.html 用 include 引入,不用在 HTML 里写复杂的 ECharts 配置,前后端分离更彻底;
业务逻辑清晰:每个函数只负责一个图表(m2 管温度折线图,m6 管饼图),符合 “单一职责”,后期改某个图表只需动对应函数。
程序运行
准备数据:把 20212.xlsx 放到 data 文件夹,确认文件名和路径正确(如果报错 “找不到文件”,检查路径是否是 “data/20212.xlsx”);
启动服务:在 PyCharm 中右键运行 app.py,看到终端输出 “Running on http://0.0.0.0:5000/” 表示成功;
访问大屏:打开浏览器,输入 “http://127.0.0.1:5000”;
完整资源
通过网盘分享的文件:
海洋数据
链接:https://pan.baidu.com/s/1G-dJd8o5z4nSuhZmokFyDw?pwd=0331 提取码: 0331
--来自百度网盘超级会员v4的分享
总结:用 Flask 搭大屏,简约而不简单
数据分析与可视化的核心魅力,从来不是 “画出多精致的图表”,而是把 “藏在 Excel 格子里的冰冷数字”,变成 “能被理解、能落地的信息线索”。就像这次用到的 2021 年气象数据,最初只是一堆包含 “风速、波高、气温” 的原始记录,没有标题,没有注释,甚至夹杂着无效值。但当我们用 Flask 搭起服务,用图表把 “月份温度变化”“风速与波高的关联” 拆解开时,这些数字突然有了意义:它不再是枯燥的监测记录,而是能帮人直观看到 “某段时间海洋环境趋势” 的素材。很多时候,技术像是工具,数据更像是线索,真正重要的应该是把线索串成能看懂的逻辑。
我一直觉得,不是只有复杂框架、海量代码才能做可视化大屏。就像这次的教程,app.py15 行核心代码,index.html 用模块化拼出大屏,chart.py 专注数据处理,没有花里胡哨的特效,却能让小白跟着步骤摸到 “数据→处理→可视化” 的全流程。有句话说得好:好的技术分享,是把‘自己踩过的坑’变成‘别人少走的路’,也别把技术架得太高,能让更多人用起来,能解决实际问题,才是真的有用。
这也许就是技术分享中的难能可贵:把自己的收获,变成别人的起点;把数据里的洞察,变成能上手的实操,让更多人感受到 “数据不只是数字,技术也不只是代码”。
注:本文仅用于技术交流与学习,请勿用于商业用途或违规操作。欢迎大家交流不同思路,若有疏漏(比如大屏排版问题),也请多多包涵~