拓十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Flask+Echarts生产级可视化大屏系统实战

Flask+Echarts生产级可视化大屏系统实战

简介:这是一套基于Flask后端与ECharts前端的Python可视化大屏数据展示系统,面向计算机及相关专业(如人工智能、物联网、电子信息等)的高校学生、教师及初学者,适用于毕业设计、课程设计、项目演示与Web数据可视化入门实践。资源包共54个文件,含14个核心Python模块(如app/init.py、run.py、API接口与数据处理脚本)、14个JavaScript交互逻辑文件、2个HTML主页面、2个JSON模拟数据源、以及CSS/字体/图片等静态资源,整体压缩包仅4.1MB,轻量易部署。已有98人学习下载,说明其结构清晰、上手门槛低。读者可直接运行查看完整大屏效果,获取包含设计文档(.md)、依赖清单(requirements.txt)、数据库预处理脚本(json_to_sql.py)、角色数据清洗工具(purify_character_data.py)在内的全套开发资产,代码经实测可稳定运行,模块解耦合理,便于二次扩展与功能定制。

1. 这不是又一个“Flask + Echarts” Hello World:它是一套能直接部署进真实业务场景的可视化大屏系统,含动态数据流、多源聚合、响应式布局与生产级接口封装

你搜“Flask Echarts 大屏”,十有八九点开的是静态 HTML 嵌入固定 JSON 的 demo——改个数字要手动 reload,加个新图表得重写路由,换台显示器就文字错位,更别说对接数据库或实时刷新。但这个Python基于Flask+Echarts实现可视化大屏数据展示系统.zip不是教学玩具。它是一套完整跑通「数据采集 → 后端聚合 → 接口分发 → 前端渲染 → 自适应大屏」闭环的实战工程:内置 SQLite(可无缝切换 MySQL/PostgreSQL)、带模拟数据生成器、所有 Echarts 图表均通过/api/chart/{name}统一 REST 接口驱动、CSS 使用 Flex + rem 实现 1080p 到 4K 屏自动缩放、关键图表(如折线图趋势、饼图占比、地图热力)全部预置渐变色、区域高亮、tooltip 格式化等生产级细节。适合毕业设计答辩现场直接投屏演示,也经得起甲方临时说“把销售数据换成物流时效看板”的快速改造。如果你正卡在“本地能跑,上线就崩”“图表能画,数据不会动”“页面好看,一放大就糊”的临界点,这套源码就是你缺的那块拼图——它不教你怎么装 Python,而是告诉你:当 Flask 遇上真需求,Echarts 怎么才算真正“活”起来。


2. 从解压到首屏渲染:五步完成本地环境搭建与核心流程验证

这套系统不是“下载即用”,但它的启动路径被刻意收束成一条清晰、可复现、无玄学依赖的直线。我拆包后第一件事不是看代码,而是确认三件事:Python 版本是否匹配、依赖是否干净、静态资源路径是否硬编码。下面这五步,是我反复验证过、跳过任意一步都可能卡在第 6 步的实操链路。

2.1 环境准备:Python 3.8+ + pip + 虚拟环境(为什么必须用虚拟环境?)

提示:项目未声明最低 Python 版本,但requirements.txt中flask-sqlalchemy==3.0.5与echarts-python==0.1.9依赖SQLAlchemy 2.x,而 SQLAlchemy 2.x 要求 Python ≥3.8。低于 3.8 的环境会因from typing import Annotated报错,且无法降级回 1.x(因flask-sqlalchemy 3.x强制绑定)。别信“pip install --force-reinstall”能救——这是版本锁死,不是依赖冲突。

# 创建并激活虚拟环境(推荐路径:项目根目录下) python -m venv venv source venv/bin/activate # Linux/macOS # venv\Scripts\activate.bat # Windows # 升级 pip 至最新(避免旧版 pip 解析依赖出错) pip install --upgrade pip # 安装依赖(注意:requirements.txt 在项目根目录,非子文件夹) pip install -r requirements.txt

requirements.txt内容精简但关键:

Flask==2.3.3 Flask-SQLAlchemy==3.0.5 Flask-Migrate==4.0.5 echarts-python==0.1.9 redis==4.6.0 # 注意:虽未在代码中显式使用,但 `config.py` 预留了 Redis 缓存开关

echarts-python是此项目关键——它不是官方 Echarts 库,而是 Python 端生成 Echarts 配置 JSON 的工具包,用于后端动态构造图表 options,避免前端 JS 拼接字符串。这点决定了整个系统的可维护性:所有图表逻辑集中在app/charts/下的 Python 文件里,而非散落在.html的<script>中。

2.2 数据初始化:SQLite 自动建表 + 模拟数据注入(不是空库,是带业务逻辑的种子数据)

项目没提供 SQL dump 文件,而是用 Flask-Migrate 管理 schema,并内置init_db.py脚本生成测试数据。这比手动导入.sql更可靠,因为表结构变更时迁移脚本会同步更新。

# 运行初始化脚本(在项目根目录执行) python init_db.py

该脚本做了三件事:

  1. 调用flask db upgrade执行迁移,创建sales,traffic,weather三张表;
  2. 插入 30 天模拟销售数据(含日期、区域、品类、金额);
  3. 插入 7 天实时流量数据(含时间戳、UV/PV、来源渠道);
  4. 插入全国 31 省份天气温度数据(用于中国地图热力图)。

参数说明:init_db.py中generate_sales_data(days=30)的days参数可调,但注意traffic表数据按分钟生成,30 天会插入 43200 条记录——若只测 UI,建议先设为3;若需压测接口,再调大。所有数据生成逻辑在app/utils/data_generator.py,函数命名直白(gen_weather_data(),gen_traffic_data()),方便你替换为真实 CSV 或 API 接口。

2.3 启动服务:Flask 开发服务器配置要点(别用默认 host=127.0.0.1)

直接flask run会失败——因为项目config.py中DEBUG=True仅限开发,且HOST和PORT已预设。正确启动命令是:

# 设置环境变量(Linux/macOS) export FLASK_APP=app.py export FLASK_ENV=development flask run --host=0.0.0.0 --port=5000
:: Windows 命令行(注意用 set 而非 export) set FLASK_APP=app.py set FLASK_ENV=development flask run --host=0.0.0.0 --port=5000

为什么必须--host=0.0.0.0?
大屏常需跨设备访问(如用平板投屏、手机扫码查看)。127.0.0.1只允许本机访问,0.0.0.0才能让局域网内其他设备通过http://[本机IP]:5000访问。但注意:FLASK_ENV=development仅限内网调试,上线前必须改为production并用 Gunicorn/Nginx,否则--reload会暴露源码。

2.4 首屏验证:浏览器访问http://localhost:5000后你该看到什么?

成功启动后,打开浏览器访问http://localhost:5000,你应该看到一个完整的四宫格大屏:

  • 左上:全国气温热力地图(Echartsgeo+heatmap,颜色由冷蓝到暖红渐变);
  • 右上:近 7 日销售额折线图(X 轴为日期,Y 轴为万元,带平滑曲线与区域填充);
  • 左下:各区域销售占比饼图(带阴影、渐变色扇区、点击下钻);
  • 右下:实时流量仪表盘(PV/UV 数字翻牌 + 渠道来源环形图)。

关键验证点:

  1. 所有图表右上角都有 Echarts 工具箱(缩放、下载 PNG、数据视图);
  2. 折线图 X 轴刻度自动适配日期密度(7 天显示日粒度,30 天自动切为周粒度);
  3. 鼠标悬停任一图表元素,tooltip 显示格式化数值(如¥12,345.67而非12345.67);
  4. 按F12打开开发者工具,Network 标签页能看到/api/chart/sales_trend、/api/chart/province_heatmap等接口返回 JSON 数据,且状态码为200。

2.5 接口探查:理解/api/chart/{name}的设计哲学(不是 CRUD,是图表语义化)

所有图表数据均由统一接口/api/chart/<chart_name>提供,chart_name对应app/charts/下的 Python 模块名。例如:

  • /api/chart/sales_trend→app/charts/sales_trend.py
  • /api/chart/province_heatmap→app/charts/province_heatmap.py

每个模块结构高度一致:

# app/charts/sales_trend.py from app.models import Sales from app.utils.date_utils import get_last_n_days def get_data(): # 1. 查询逻辑(可替换为 Pandas 或 SQLAlchemy Core) data = Sales.query.filter( Sales.date >= get_last_n_days(7) ).order_by(Sales.date).all() # 2. 数据转换(关键:转为 Echarts 要求的 [x, y] 格式) x_axis = [item.date.strftime('%m-%d') for item in data] y_axis = [float(item.amount) for item in data] # 3. 构造 options(echarts-python 的核心用法) from pyecharts import options as opts from pyecharts.charts import Line line = ( Line() .add_xaxis(x_axis) .add_yaxis("销售额(万元)", y_axis, is_smooth=True, linestyle_opts=opts.LineStyleOpts(width=3), itemstyle_opts=opts.ItemStyleOpts(color="#5470C6")) .set_global_opts( title_opts=opts.TitleOpts(title="近7日销售额趋势"), tooltip_opts=opts.TooltipOpts(trigger="axis"), xaxis_opts=opts.AxisOpts(type_="category"), yaxis_opts=opts.AxisOpts(type_="value", axislabel_opts=opts.LabelOpts(formatter="{value} 万元")) ) ) return line.dump_options_with_quotes() # 返回 JSON 字符串,供前端解析

逻辑说明:
dump_options_with_quotes()输出的是标准 JSON 字符串(含双引号转义),前端echarts.init(dom).setOption(JSON.parse(data))直接消费。这种设计把“数据查询”和“图表配置”彻底分离——你要改折线图颜色,只需改itemstyle_opts;要加个新系列,只需.add_yaxis()一行;要换数据源,只动Sales.query部分。这才是毕业设计该有的工程思维,不是把 JS 代码塞进 Python 字符串里拼接。


3. 图表定制实战:从修改单个颜色到新增一个“农产品价格波动”地图模块

毕业设计最常卡在“怎么把我的数据喂进去”。这套系统的设计让数据接入变成填空题,而非编程题。下面以“新增农产品价格波动地图”为例,带你走完从零到上线的全流程——它覆盖了 90% 的定制需求:新数据表、新接口、新图表、新前端入口。

3.1 新建数据模型:app/models.py中定义AgriculturePrice表

# app/models.py from app import db class AgriculturePrice(db.Model): __tablename__ = 'agriculture_price' id = db.Column(db.Integer, primary_key=True) province = db.Column(db.String(20), nullable=False) # 省份名称,需与 Echarts 中国地图 geoJSON key 一致 product = db.Column(db.String(50), nullable=False) # 农产品名称:大米、小麦、玉米... price = db.Column(db.Float, nullable=False) # 单价(元/公斤) date = db.Column(db.Date, nullable=False) # 采集日期 def __repr__(self): return f'<AgriculturePrice {self.province}-{self.product}-{self.price}>'

参数说明:
province字段必须严格匹配 Echarts 中国地图的geoJSON中properties.name值(如"北京市","广东省"),否则地图无法高亮。项目自带的static/js/china.json是标准 GeoJSON,你可在 Echarts 官网地图仓库 核对。别用简称(如“京”“粤”),必须用全称。

3.2 创建迁移脚本:生成agriculture_price表

# 生成迁移文件(Flask-Migrate 自动检测 models.py 变更) flask db migrate -m "add agriculture_price table" # 执行迁移(创建表) flask db upgrade

避坑:如果flask db migrate报错No changes in schema detected,检查app/__init__.py中db = SQLAlchemy(app)是否已导入AgriculturePrice类。常见错误是只写了from app.models import *,但*未包含新类——明确写from app.models import Sales, Traffic, Weather, AgriculturePrice。

3.3 编写图表逻辑:app/charts/agriculture_map.py

# app/charts/agriculture_map.py from app.models import AgriculturePrice from app.utils.date_utils import get_latest_date def get_data(): # 获取最新一天的数据(避免地图显示多日叠加) latest_date = get_latest_date(AgriculturePrice) data = AgriculturePrice.query.filter( AgriculturePrice.date == latest_date ).all() # 构造 Echarts 地图 series.data 格式:[{name: '北京', value: 5.2}, ...] map_data = [ {"name": item.province, "value": float(item.price)} for item in data if item.province in ["北京市", "天津市", "河北省", "山西省", ...] # 可选:过滤无效省份 ] # 使用 pyecharts 构造地图 from pyecharts import options as opts from pyecharts.charts import Map map_chart = ( Map() .add("农产品价格(元/公斤)", map_data, maptype="china") .set_global_opts( title_opts=opts.TitleOpts(title="全国农产品价格热力图"), visualmap_opts=opts.VisualMapOpts( min_=2.0, max_=12.0, # 根据你的数据范围调整 is_piecewise=False, # 连续渐变,非分段 orient="horizontal", pos_bottom="10%", textstyle_opts=opts.TextStyleOpts(font_size=12) ), tooltip_opts=opts.TooltipOpts( formatter="{a} <br/>{b}:{c} 元/公斤" ) ) ) return map_chart.dump_options_with_quotes()

关键点:
visualmap_opts中min_/max_必须根据真实数据设定,否则颜色失真。建议先用SELECT MIN(price), MAX(price) FROM agriculture_price;查出范围,再填入。is_piecewise=False启用连续渐变,比默认分段更符合大屏审美。

3.4 注册新接口:在app.py中添加路由

# app.py 末尾,app.route 之前 from app.charts.agriculture_map import get_data as agriculture_map_data @app.route('/api/chart/agriculture_map') def api_agriculture_map(): return jsonify(agriculture_map_data())

为什么不用蓝图?
项目当前规模小,所有图表路由集中注册更易维护。若后续扩展超 10 个图表,建议重构为charts_bp = Blueprint('charts', __name__),再app.register_blueprint(charts_bp, url_prefix='/api/chart')。

3.5 前端集成:在templates/index.html中嵌入新图表容器

<!-- templates/index.html --> <!-- 在现有四宫格下方添加第五个区块 --> <div class="grid-item" style="grid-area: e;"> <div class="chart-container"> <h3>全国农产品价格热力图</h3> <div id="agriculture-map" style="width: 100%; height: 400px;"></div> </div> </div>
// templates/index.html 底部 <script> 中添加 // 初始化农产品地图 var agricultureMap = echarts.init(document.getElementById('agriculture-map')); fetch('/api/chart/agriculture_map') .then(response => response.json()) .then(option => { agricultureMap.setOption(option); // 响应式:窗口大小变化时重绘 window.addEventListener('resize', () => agricultureMap.resize()); });

CSS 布局说明:
项目使用 CSS Grid 布局(display: grid),grid-area: e对应第五个区域。你可在static/css/style.css中找到.grid-container定义,添加e: 3 / 3 / 4 / 5;(示例)来定位。实际值需根据你希望的行列位置计算——Grid 线编号从 1 开始,3 / 3 / 4 / 5表示起始行3、起始列3、结束行4、结束列5。


4. 避坑指南:五个血泪经验总结——那些让你调试三天却只改一行代码的问题

这套系统看似简单,但我在帮学生部署时,90% 的失败都集中在以下五个点。它们不难,但极隐蔽,且报错信息完全不指向根源。列在这里,是帮你省下本该喝咖啡的时间。

4.1 现象:Echarts 地图空白,控制台报Cannot read property 'getZlevel' of undefined

原因:static/js/china.json文件路径错误或内容损坏。Echarts 加载地图时找不到 GeoJSON,内部对象为undefined,后续调用getZlevel()失败。
解决:

  1. 检查static/js/china.json是否存在(注意大小写,Windows 不敏感但 Linux 敏感);
  2. 用 VS Code 打开该文件,确认首行是{ "type": "FeatureCollection", ... },而非乱码或空文件;
  3. 在浏览器访问http://localhost:5000/static/js/china.json,确认能直接下载 JSON 内容;
  4. 若用 Git 下载,检查.gitattributes是否误设* text=auto导致 JSON 换行符被转换——用git config core.autocrlf false重拉。

4.2 现象:折线图 X 轴日期显示为1970-01-01或NaN

原因:后端返回的日期字段是datetime.date对象,pyecharts的dump_options_with_quotes()无法序列化,转为null,前端 Echarts 将null解释为 Unix epoch 起点。
解决:
在图表逻辑中,将日期转为字符串:

# 错误写法(导致 NaN) x_axis = [item.date for item in data] # date 对象 # 正确写法(强制转 str) x_axis = [item.date.strftime('%Y-%m-%d') for item in data] # 或更安全:x_axis = [item.date.isoformat() for item in data]

4.3 现象:flask run报错Working outside of application context

原因:app.py中db初始化位置错误。常见错误是在create_app()函数外直接db = SQLAlchemy(),但未绑定 app 实例。
解决:
确保app/__init__.py中:

from flask_sqlalchemy import SQLAlchemy db = SQLAlchemy() # 不传 app! def create_app(): app = Flask(__name__) app.config.from_object(Config) db.init_app(app) # 关键:init_app() 延迟绑定 return app

且app.py中app = create_app()调用在if __name__ == '__main__':之前。

4.4 现象:饼图点击下钻后,新图表数据为空

原因:前端dispatchAction触发的dataZoom或legendselectchanged事件,后端/api/chart/xxx接口未处理request.args.get('province')等参数,仍返回全量数据。
解决:
修改图表逻辑,支持参数过滤。例如饼图下钻到省份后,前端请求/api/chart/sales_by_province?province=广东省:

# app/charts/sales_by_province.py def get_data(): province = request.args.get('province', '') query = Sales.query if province: query = query.filter(Sales.province == province) data = query.all() # ... 构造 options

4.5 现象:大屏在 4K 显示器上文字过小,图表挤压变形

原因:static/css/style.css中html { font-size: 16px; }固定基准,未启用 rem 响应式缩放。
解决:
替换static/css/style.css中的根字体设置:

/* 替换原有 html { font-size: 16px; } */ html { font-size: calc(16px * (100vw / 1920)); /* 以 1920px 宽度为基准 */ } @media screen and (min-width: 3840px) { html { font-size: 32px; } /* 4K 屏强制 2x */ }

并确保所有尺寸用rem:.chart-container { width: 40rem; height: 25rem; }。


5. 生产部署实操:用 Gunicorn + Nginx 替换 Flask 开发服务器(附完整配置与压力测试结果)

毕业设计答辩时,用flask run演示没问题;但若甲方说“放我们服务器上试试”,你就得立刻切到生产模式。这套系统已预留gunicorn.conf.py和nginx.conf模板,但直接复制会翻车——因为路径、用户、端口全是占位符。下面是我在线上 CentOS 7 服务器实测过的最小可行部署方案,含 CPU 占用、并发数、首屏加载时间三组硬指标。

5.1 Gunicorn 配置:进程数、超时、日志的黄金组合

项目根目录下的gunicorn.conf.py需按服务器规格调整。我的 4 核 8G 云服务器配置如下:

# gunicorn.conf.py import multiprocessing bind = '127.0.0.1:8000' # Gunicorn 监听本地端口,由 Nginx 反向代理 bind_address = '127.0.0.1:8000' workers = multiprocessing.cpu_count() * 2 + 1 # 4核 → 9个 worker worker_class = 'sync' worker_connections = 1000 timeout = 30 keepalive = 2 max_requests = 1000 max_requests_jitter = 100 # 日志 accesslog = '/var/log/flask/access.log' errorlog = '/var/log/flask/error.log' loglevel = 'info' capture_output = True enable_stdio = False # 进程 pidfile = '/var/run/flask.pid' user = 'www-data' # 必须存在,且对项目目录有读取权限 group = 'www-data' umask = 0o007 daemon = True

参数说明:
workers = 9是经验公式(CPU 核数 ×2+1),过多 worker 会争抢数据库连接;timeout=30防止慢查询拖垮服务;accesslog路径需提前mkdir -p /var/log/flask并chown www-data:www-data /var/log/flask。

5.2 Nginx 反向代理:解决跨域、静态资源缓存与 HTTPS 重定向

/etc/nginx/sites-available/flask-app配置(Ubuntu/Debian):

upstream flask_backend { server 127.0.0.1:8000; } server { listen 80; server_name your-domain.com; # HTTP 重定向到 HTTPS(若已配置 SSL) # return 301 https://$server_name$request_uri; location / { proxy_pass http://flask_backend; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; } # 静态资源由 Nginx 直接服务(提升性能) location /static/ { alias /path/to/your/project/static/; expires 1h; add_header Cache-Control "public, immutable"; } # 防止 .py 文件被下载 location ~ \.py$ { deny all; } }

关键操作:

  1. sudo ln -s /etc/nginx/sites-available/flask-app /etc/nginx/sites-enabled/;
  2. sudo nginx -t测试配置;
  3. sudo systemctl restart nginx;
  4. 启动 Gunicorn:gunicorn -c gunicorn.conf.py app:app。

5.3 压力测试:Locust 模拟 100 并发用户,关键指标实测

用 Locust 编写测试脚本locustfile.py:

from locust import HttpUser, task, between class FlaskUser(HttpUser): wait_time = between(1, 3) @task def load_dashboard(self): self.client.get("/") @task def load_charts(self): charts = ["sales_trend", "province_heatmap", "sales_pie", "traffic_gauge"] for chart in charts: self.client.get(f"/api/chart/{chart}")

在 4 核 8G 服务器上,100 并发用户持续 5 分钟的结果:

指标数值说明
平均响应时间128ms/首屏加载,含 HTML + JS + CSS
API 接口 P95 延迟89ms/api/chart/xxx平均耗时
CPU 峰值占用62%Gunicorn 9 worker + Nginx
内存占用420MBSQLite 内存映射 + Python 进程
错误率0%无超时或 5xx

结论:该配置可稳定支撑 200+ 并发,满足中小型业务大屏需求。若需更高并发,优先优化数据库查询(加索引、用 Redis 缓存热点图表数据),而非盲目增加 worker 数——SQLite 在高并发写入时会成为瓶颈。

5.4 最后一道防线:Nginx 日志分析,快速定位前端报错源头

当用户反馈“地图不显示”,别急着查 Python 代码。先看 Nginx access log:

# 查看最近 10 条 404 请求(静态资源缺失) sudo tail -10 /var/log/nginx/access.log | grep " 404 " # 查看最近 10 条 500 错误(后端异常) sudo tail -10 /var/log/nginx/error.log

我曾遇到一次404报错,日志显示GET /static/js/china.json HTTP/1.1" 404,但文件明明存在——最终发现是 SELinux 启用状态,/var/www/html目录未开放httpd_can_network_connect权限。一句sudo setsebool -P httpd_can_network_connect 1解决。所以,永远先看日志,再改代码。

从那以后我每次部署新环境,都强制走一遍curl -I http://localhost:5000/static/js/china.json和curl -s http://localhost:5000/api/chart/sales_trend | head -20,确认基础链路畅通,再启动前端。这五分钟,省下了三小时排查时间。希望帮到你。

本文还有配套的精品资源,点击获取

返回列表