ARTICLE DETAIL

资讯详情

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

用Python制作二氧化碳排放可视化大屏:从数据清洗到部署避坑指南

用Python制作二氧化碳排放可视化大屏:从数据清洗到部署避坑指南 简介面向Python数据分析与可视化学习者的二氧化碳排放趋势大屏工程重点解决从原始CSV到交互式Web看板的完整链路问题。工程实践覆盖数据导入、清洗与缺失值处理利用pandas完成时间序列重采样和地区分组统计并配合matplotlib/seaborn绘制排放趋势图、柱状对比图进一步通过Streamlit构建大屏支持动态选择时间段与国家地区多图联动直观展示排放变化与区域差异适用课程设计、科研报告或环保科普等场景。压缩包共3个文件包含2份CSV数据源一份为历史总览、一份按国家/地区细分和1个Python主脚本整体约1.83MB轻量紧凑代码结构清晰便于逐行理解。已有1495人学习适合具备基础Python语法、希望进阶数据分析与可视化的开发者工程稍作改造即可迁移至其他环境指标的大屏展示是一份上手快、可扩展的实战参考。1. 一块二氧化碳可视化大屏真正难的不是画图接到「用 python 制作可视化大屏分析二氧化碳排放趋势和影响」这个需求很多人第一反应是去找大屏模板、调颜色、加特效。我做过几轮之后可以给你交个底图表渲染只占两成工作量剩下八成全押在两件事上——数据口径能不能对齐趋势与影响分析经不经得起被追问。大屏投到指挥中心墙上第一眼是视觉第二眼是数字第三眼就是问题你这个总量是万吨还是亿吨增速算的是同比还是环比脱钩指数到底是变大还是变小了这篇文章按我自己的落地路径来写先理顺碳排放数据的口径和趋势算法再选型确定用 pyecharts 还是前端大屏可视化编辑器然后带你从一张趋势面积图开始拼出完整的 1920×1080 大屏最后把内网部署、分辨率适配、数据刷新这些坑一个个填掉。适合手里有 pandas 基础、需要交付一块真能上墙的碳排看板的人也适合想评估「这个方向值不值得自己投入」的团队。2. 先把二氧化碳数据理顺三种口径与趋势计算方法2.1 碳排放数据的三种常见口径做二氧化碳大屏第一步不是画图而是搞清楚数据是什么口径。我做过的项目里数据通常来自统计年鉴、重点企业报送、环境监测平台或者咨询机构常见口径有三种。口径核心字段典型单位常见混淆点总量口径区域/全国年度排放总量亿吨 CO2 或万吨 CO2累计值和年度值混用结构口径分能源品种、分部门排放万吨 CO2标煤量和排放量混用强度口径排放总量 / GDP吨 CO2 / 万元用当年价还是不变价 GDP总量口径解决「排了多少」的问题结构口径解决「谁在排」强度口径解决「排得划不划算」。大屏上把这三层都放进去才算扣住了标题里的「趋势和影响」。这里有个新手最容易踩的坑月度数据出现明显断裂往往不是排放真的跌了而是上月末有个「累计值」混进了当月值序列。我一般的做法是拿到数据先不急着画图先做一次物理检查按时间排序算相邻两期差值超过历史最大月变化的 3 倍就标出来人工核。大屏可以没有花哨动画但不能有一个让人当场质疑的数字。2.2 用 pandas 把乱序数据校准成可比较的时间序列假设你已经有一份 CSV包含日期、排放量、单位、部门和 GDP。下面这段是数据清洗和年度聚合的骨架可以直接跑import pandas as pd import numpy as np # 读取原始数据date 列解析成时间类型 df pd.read_csv(co2_data.csv, parse_dates[date]) df df.sort_values(date).set_index(date) # 统一排放单位到“万吨” # 单位列里常见的有亿吨、万吨、吨分别换算 df[emission_wt] np.where(df[unit] 亿吨, df[emission] * 10000, np.where(df[unit] 吨, df[emission] / 10000, df[emission])) df[gdp] df[gdp].astype(float) # 按年度聚合得到该年度总排放和平均GDP year_df df.resample(YE).agg( emission(emission_wt, sum), gdp(gdp, mean) ) # 同比增速用 pct_change 即可输出为百分数 year_df[emission_yoy] year_df[emission].pct_change() * 100 # 三年移动平均平滑掉单年异常波动 year_df[emission_ma3] year_df[emission].rolling( 3, min_periods1 ).mean()这段代码有两个地方值得盯一下。第一resample(YE)在 pandas 2.x 里是年终聚合老版本可能要写A如果你的数据是自然年度已经聚合好的这步可以直接跳过。第二pct_change()产生的第一个值是 NaN后面算脱钩指数时记得过滤别让 NaN 串进大屏 JSON。rolling(3, min_periods1)是我必写的参数。min_periods1保证前面缺数据的年份也有值可看否则 2015 年那一栏会直接空掉给前端传 null 时 ECharts 的折线会出现断点观感很差。2.3 判断排放趋势斜率和加速度比「涨了还是跌了」更实用大屏中间主图通常放总量趋势但光是「今年比去年多」解决不了判断。CO2 排放最关心的是趋势方向是上行还是下行增速是在加快还是在放缓。用numpy.polyfit做一阶和二阶拟合比单独看某一年波动靠谱得多。import numpy as np x np.arange(len(year_df)) # 0,1,2,... 对应年份顺序 y year_df[emission].values # 年度排放总量万吨 # 一阶拟合y k1 * x b1斜率 k1 代表平均每年增减多少万吨 k1, b1 np.polyfit(x, y, 1) year_df[trend_line] np.polyval([k1, b1], x) # 二阶拟合y c2 * x^2 c1 * x c0 c2, c1, c0 np.polyfit(x, y, 2) # 加速度 2 * c2正数表示排放增速在加快负数表示在放缓 acceleration 2 * c2逻辑说明k1的单位是「万吨/年」比如 k1 3200说明这十年里每年平均比上一年多排放 3200 万吨。c2的正负更有意思——它是二次项的系数乘以 2 后是二阶导代表趋势本身的加速度。如果总排放还在涨但acceleration已经转负说明涨势收敛这比「年排放又创新高」这个结论更有汇报价值。参数提醒年度数据通常只有 10~30 个点样本量不大拟合出来的 R² 可以参考但不值得较真。我的习惯是把趋势线用虚线画出来并且绝不外推超过两年。领导问「明年多少」时你可以给区间但别给精确值——那是预测模型该干的事不是趋势拟合。2.4 影响分析排放强度、部门贡献与脱钩指数「影响」落到大屏上不能只写一句「排放影响气候」。我常用三个可计算的量化指标# 1. 排放强度每万元 GDP 对应的排放吨数越低说明增长质量越高 year_df[intensity] year_df[emission] / year_df[gdp] # 2. 部门贡献各行业排放占当年总排放的比例 sector_share df.groupby([df.index.year, sector])[emission_wt].sum() sector_share sector_share / sector_share.groupby(level0).transform(sum) # 3. 脱钩指数排放增速 与 GDP 增速 的比值 merged year_df.copy() merged[gdp_yoy] merged[gdp].pct_change() * 100 merged[decoupling] merged[emission_yoy] / merged[gdp_yoy]脱钩指数的含义值得在图上标清楚指数大于 1说明排放增速比经济增速还快是「高挂钩」在 0 到 1 之间是「相对脱钩」经济在增长但排放增速放缓指数小于 0 且排放增速为负才是「绝对脱钩」。计算时注意过滤gdp_yoy接近 0 的年份否则一个除法就能把图炸出天际。部门贡献适合用堆叠柱状图或占比折线看结构变迁排放强度适合和 GDP 增速做双轴图。这两个图我会在第 4 章放上大屏。数据这一步做完后面所有图表都只是把你已经算好的结论可视化而不是在图表里临时算。3. 选型pyecharts 全栈还是前端大屏可视化编辑器3.1 两种技术路线的边界大屏可视化编辑器这几年很火拖拖拽拽就能出图确实省事。但回到这个标题——用 python 制作可视化大屏分析二氧化碳排放趋势和影响——你大概率已经有数据清洗和趋势计算写在 Python 里了。与其把算好的结果再手动粘进编辑器不如考虑两条更顺的路线。维度方案 Apyecharts 全栈生成 HTML方案 BPython 做接口 前端 ECharts学习成本低只会 Python 也能交付需要一点 HTML/JS 基础交付速度当天出第一版前后端联调多花 1~2 天实时刷新静态文件配定时重跑或 meta refresh效果好适合频繁变动数据内网离线要把 JS 资源本地化同样要本地化二次开发图表配置是 Python 字典前端可以写任意交互我一般怎么选数据量小、展示为主、团队里没有前端直接走方案 A用 pyecharts 的 Page 拖拽布局出大屏交付一个final.html就能跑。如果后续要做用户权限、多指标切换、真实时数据老老实实方案 B——Python 只负责吐 JSON前端 ECharts 负责画。别指望一个编辑器能替你处理「碳排口径随年份调整」这类业务逻辑它只解决布局问题解决不了数据可信问题。3.2 大屏的图表布局与信息层级大屏不是把所有图塞满就完事。CO2 主题大屏我建议按「中间结论、左右证据」来排布。中间放最核心的总量趋势领导进来第一眼就看到排放是在爬升还是掉头左边放结构证据能源品种、部门排放回答「谁在排」右边放影响证据排放强度、脱钩指数回答「排放和经济的关系」。以 1920×1080 为例我常用的栅格划分如下区域占屏宽放什么图信息作用顶部100%标题栏、时间范围、关键指标卡一眼定位年份和总量左列24%能源品种饼图、分部门条形图结构分析中间52%排放总量趋势面积图核心趋势右列24%排放强度与 GDP 增速双轴图、脱钩指数影响分析第一次做别贪多4~5 张图足够。大屏最容易翻车的不是缺图而是信息过载每张图都在喊「看我」最后一块都记不住。3.3 跑通最小流程需要的文件清单文件作用co2_data.csv原始排放和 GDP 数据process_data.py清洗、聚合、趋势与脱钩计算build_dashboard.py生成图表并拼装大屏co2_dashboard_render.html拖拽布局用的中间产物co2_dashboard.html最终交付的大屏文件建议把数据清洗和图表生成拆成两个脚本。数据口径调整时只改process_data.py图表版式调整时只碰build_dashboard.py。混在一起写的脚本三个月后再看就是黑匣子改一个数字可能连带图表全崩。4. 用 pyecharts 制作二氧化碳大屏从趋势图到整页交付4.1 环境准备与主题初始化环境上我没太多可说的装好 pyecharts 和 pandas 就能开始vscode 里记得确认 Python 解释器和你 pip 安装包用的是同一个环境。新版本 pyecharts 的导入路径是from pyecharts.charts import Line老教程里from pyecharts import Line那套已经过时了照着写会直接 ImportError。from pyecharts import options as opts from pyecharts.charts import Line, Pie, Bar, Page # 2022 年之后 pyecharts 2.x 的初始化参数 init opts.InitOpts( width1200px, height420px, themedark, # 内置暗色主题适合大屏 bg_color#0b1220 # 深蓝黑背景和指挥中心屏幕更搭 )themedark只是给了一个基础暗色底子实际大屏的配色我通常会自己在每个系列上单独指定不然系统默认配色会显得「很 pyecharts」。bg_color用纯色深蓝黑#0b1220比纯黑更有层次也方便后续在 CSS 里统一背景渐变。4.2 主图排放趋势面积图中间主图用面积图最直观颜色填充让趋势方向一目了然。下面代码直接承接第 2 章算好的year_dfyears year_df.index.year.astype(str).tolist() emission_total year_df[emission].round(0).tolist() emission_ma3 year_df[emission_ma3].round(0).tolist() trend_line ( Line(init_optsopts.InitOpts( width1200px, height420px, themedark, bg_color#0b1220 )) .add_xaxis(years) .add_yaxis( 排放总量, emission_total, is_smoothTrue, symbolcircle, symbol_size5, areastyle_optsopts.AreaStyleOpts( opacity0.35, color#fbbf24 ), linestyle_optsopts.LineStyleOpts( width3, color#fbbf24 ), label_optsopts.LabelOpts(is_showFalse), ) .add_yaxis( 三年移动平均, emission_ma3, is_smoothTrue, symbolnone, linestyle_optsopts.LineStyleOpts( width2, color#38bdf8, type_dashed ), label_optsopts.LabelOpts(is_showFalse), ) .set_global_opts( title_optsopts.TitleOpts( title二氧化碳排放总量趋势, subtitle单位万吨 CO2虚线为三年移动平均, pos_leftcenter ), tooltip_optsopts.TooltipOpts( triggeraxis, axis_pointer_typecross ), datazoom_opts[opts.DataZoomOpts( range_start0, range_end100 )], legend_optsopts.LegendOpts(pos_top2%), xaxis_optsopts.AxisOpts( name年份, axislabel_optsopts.LabelOpts(interval0) ), yaxis_optsopts.AxisOpts( name万吨, splitline_optsopts.SplitLineOpts(is_showTrue) ), ) )逻辑说明第一条系列是真实排放总量加了 0.35 透明度的面积填充用来表达「水位」第二条是三年移动平均用虚线用来表达「趋势」。这两条线叠在一起观众能同时看到原始波动和趋势方向比单独一条折线信息量大很多。参数说明datazoom_opts默认是开启滚动缩放的手柄大屏上鼠标操作不频繁我的习惯是把range_start0, range_end100固定住保证一开始显示全部年份用户不拖动也不会被截断。symbolnone让移动平均线不带数据点避免和图例挤在一起。tooltip用triggeraxis而不是默认的item鼠标扫过时能看到两条线同一年的数据汇报时体验好很多。4.3 结构图能源构成饼图与部门条形图左侧两张图解决「结构」问题。能源品种排放用玫瑰饼图部门排放用横向条形图或普通条形图。代码如下# 分能源品种排放数据格式为 [(名称, 值), ...] energy_items [ (煤炭, 48210), (石油, 17520), (天然气, 9320), (非化石能源, 6230) ] pie_chart ( Pie(init_optsopts.InitOpts( width520px, height320px, themedark, bg_color#0b1220 )) .add( 排放量, energy_items, radius[28%, 68%], center[50%, 52%], rosetyperadius, label_optsopts.LabelOpts( formatter{b}\n{d}%, color#e2e8f0 ) ) .set_global_opts( title_optsopts.TitleOpts( title分能源品种排放结构, pos_leftcenter ), legend_optsopts.LegendOpts(pos_bottom0%) ) ) # 分部门排放 sector_names [电力热力, 工业, 交通, 建筑, 居民生活] sector_values [42100, 18800, 8200, 3650, 1980] bar_chart ( Bar(init_optsopts.InitOpts( width520px, height320px, themedark, bg_color#0b1220 )) .add_xaxis(sector_names) .add_yaxis( 排放量, sector_values, category_gap38%, itemstyle_optsopts.ItemStyleOpts( coloropts.LinearGradientOpts( xaxis_0, yaxis_0, xaxis1_0, yaxis1_1, color_list[#facc15, #f97316] ) ), label_optsopts.LabelOpts( is_showTrue, positiontop, color#e2e8f0 ) ) .set_global_opts( title_optsopts.TitleOpts( title分部门排放量, pos_leftcenter ), xaxis_optsopts.AxisOpts( axislabel_optsopts.LabelOpts(rotate-15) ), yaxis_optsopts.AxisOpts(name万吨) ) )参数说明rosetyperadius让饼图的半径随数值变化比普通饼图更能突出煤炭这类大头formatter{b}\n{d}%同时显示名称和百分比大屏上比图例可读性强。条形图的category_gap38%控制柱子间距间距太小会显得拥挤太大则浪费横向空间。LinearGradientOpts里的xaxis_和yaxis1_是渐变的起点和终点坐标我给的是从上到下渐变适合垂直柱状图。部门超过 8 个时记得给 x 轴加datazoom否则底下的部门名字会叠成一团。4.4 影响分析组合图排放强度与 GDP 增速双轴右侧放「影响」。最实用的是双轴图柱状图显示排放强度吨 CO2/万元 GDP折线叠加 GDP 增速一眼看出二者是否脱钩。from pyecharts.charts import Bar as BarOverlay, Line as LineOverlay intensity_values year_df[intensity].round(2).tolist() gdp_growth_values year_df[gdp_yoy].round(1).fillna(0).tolist() strength_bar ( BarOverlay(init_optsopts.InitOpts( width520px, height320px, themedark, bg_color#0b1220 )) .add_xaxis(years) .add_yaxis( 排放强度, intensity_values, yaxis_index0, color#10b981, label_optsopts.LabelOpts(is_showFalse) ) .extend_axis( yaxisopts.AxisOpts( nameGDP增速(%), type_value, positionright, axislabel_optsopts.LabelOpts(formatter{value}%) ) ) .set_global_opts( title_optsopts.TitleOpts( title排放强度与GDP增速, pos_leftcenter ), tooltip_optsopts.TooltipOpts(triggeraxis), ) ) gdp_line ( LineOverlay(init_optsopts.InitOpts( width520px, height320px, themedark, bg_color#0b1220 )) .add_xaxis(years) .add_yaxis( GDP增速, gdp_growth_values, yaxis_index1, color#22d3ee, symbolcircle, symbol_size5, label_optsopts.LabelOpts(is_showFalse) ) ) combo strength_bar.overlap(gdp_line)逻辑说明extend_axis在右侧生成第二条 y 轴但右侧轴默认只挂在 Bar 上所以 GDP 增速折线要用yaxis_index1指定走右侧轴。两条数据的量级差很多——排放强度可能在个位数GDP 增速在个位数百分比——不分开坐标轴的话折线会被压成一条水平线。参数说明fillna(0)把第一年的 NaN 补成 0是因为没有上一年数据就无法算增速大屏上总不能留个空洞。overlap是 pyecharts 2.x 里把两个 chart 叠加的标准做法比手写Grid简单适合这种「一把柱一根线」的组合图。4.5 把图表拼成大屏并导出固定版式四张图单独生成没问题但大屏要的是「一张整页」。pyecharts 官方推荐的拖拽布局能省掉手写 HTML 的麻烦page Page(layoutPage.DraggablePageLayout) page.add(trend_line, pie_chart, bar_chart, combo) page.render(co2_dashboard_render.html)第一步先render生成一个可拖拽页面用浏览器打开把四张图拖到你想要的位置。摆好后点页面右上角的「Save Config」会下载一个chart_config.json。然后在脚本里接着执行page.save_resize_html( sourceco2_dashboard_render.html, cfg_filechart_config.json, destco2_dashboard.html )这段代码说明save_resize_html会把拖拽好的位置、宽高固化到新文件里之后图表数据变了只要重新跑build_dashboard.py布局还是原来调好的样子不需要再拖一次。拖拽布局第一次用是有点玄学两个图表会叠在一起别慌从右上角抓住标题栏区域拖就行。提示拖拽布局适合做「一次性固定版式」。如果后面要频繁改布局页面中央那套自动缩放脚本会干扰拖拽建议改好布局后再接分辨率适配。5. 大屏制作避坑记录5 个最常翻车的现场5.1 内网部署白屏ECharts 的 CDN 资源被拦现象本地打开co2_dashboard.html一切正常拷到内网服务器上双击变成白屏控制台报一堆net::ERR_FAILED。原因pyecharts 生成的 HTML 默认从 CDN 加载 ECharts 脚本和主题资源。内网环境访问不了外网图表根本拿不到渲染引擎。解决在交付前就把外部资源本地化。用浏览器打开生成的 HTML搜索src和href把所有指向https://cdn.jsdelivr.net和https://assets.pyecharts.org的链接下载到项目根目录的assets/文件夹然后把 HTML 里的引用路径改成assets/xxx.js这种相对路径。pyecharts 引用的 JS 不止一个最稳妥的办法是下载全部后逐个替换别只替换一个 ECharts 主文件。这个操作做完内网环境随便拷永不白屏。5.2 中文字体和标签乱码现象大屏在 Windows 上中文显示正常部署到国产化终端或某些 Linux 环境的浏览器里图表的标题和标签变成方块。原因图表字体用的默认字体在目标系统不存在浏览器回退失败。解决在所有LabelOpts、TitleOpts里显式指定font_familyMicrosoft YaHei如果目标环境是 Linux改成Noto Sans CJK SC更稳。HTML 的head里也要保证有meta charsetutf-8否则读取本地文件时可能按系统默认编码解析中文直接乱掉。5.3 大屏在不同分辨率下变形现象1920×1080 上正好占满一屏换到 1366×768 的显示器右侧图被挤出屏幕底部出现滚动条。原因pyecharts 生成的是固定像素宽高的图表浏览器窗口变小后没有等比缩放。解决给大屏套一个固定 1920×1080 的容器用 JS 按视口比例缩放而不是靠 CSS 百分比硬撑。在 HTML 里加function scaleDashboard() { const el document.querySelector(.dashboard-body); const scaleW window.innerWidth / 1920; const scaleH window.innerHeight / 1080; const scale Math.min(scaleW, scaleH); el.style.transformOrigin 0 0; el.style.transform scale( scale ); } window.addEventListener(resize, scaleDashboard); scaleDashboard();Math.min保证宽高都不溢出宁可两侧留一点黑边也不能出现滚动条。这个脚本要在图表渲染完成后执行否则 ECharts 拿到的容器尺寸还是缩放前的值。5.4 数据更新了图表却还是老数据现象第二天跑了一遍脚本数据库里的值变了打开大屏还是昨天的数。原因浏览器把co2_dashboard.html缓存了或者你是手动打开的文件根本没重新生成。解决把静态方案的「刷新」做成一条流水线定时任务每天跑process_data.py重新算数据再跑build_dashboard.py生成新 HTML。页面本身加一个一小时级的自动重载meta http-equivrefresh content3600如果你走的是 FastAPI 接口方案可以在接口里吐最新 JSON前端用setInterval每 5~10 分钟重新拉一次再setOption。大屏的「实时」多数时候不是秒级需求别一上来就上 WebSocket。5.5 趋势外推的“预测”被外行当场质疑现象大屏上画了一条延伸到 2027 年的趋势虚线评审会上业务专家直接问凭什么说 2026 年就是这个数你用了什么模型原因线性趋势线天然有外推性质但年度样本只有十几年把它当预测展示容易被当成精确预测来攻击。解决趋势线只覆盖有数据的年份范围不向未来延伸。如果一定要给个方向把未来两年的趋势部分单独用灰色虚线画出来并在副标题里写「基于历史趋势外推不含政策情景」。《强加时间范围的tooltip》也别让两年后的数据点太显眼。汇报的落点是「趋势正在放缓还是加速」而不是「2027 年具体排多少万吨」。6. 交付前把大屏当产品验一遍截屏回归与数据刷新大屏做完别急着交付先当产品测一遍。我最常用的验证方法很简单用 Headless 浏览器截一张 1920×1080 的图人工看一遍有没有空白块、遮挡、图例重叠。代码不长from selenium import webdriver from selenium.webdriver.chrome.options import Options opts Options() opts.add_argument(--headless) opts.add_argument(--no-sandbox) opts.add_argument(--force-device-scale-factor1) driver webdriver.Chrome(optionsopts) driver.set_window_size(1920, 1080) driver.get(file:///D:/projects/co2_dashboard/co2_dashboard.html) driver.save_screenshot(dashboard_check.png) driver.quit()截图只是第一层。我还会在真实浏览器里打开控制台逐张图移动鼠标hover 每个数据点。ECharts 的 tooltip 在某些缩放比例下有偏移这个问题截图测不出来必须手工过一遍。确认没有 JS 报错、tooltip 位置正常再拿去投屏。如果大屏是给领导汇报用的我还有一个习惯把所有图表的单位写进副标题里。总量是「万吨 CO2」强度是「吨 CO2/万元 GDP」部门占比是「占当年总排放比例」。单位不写清楚大屏上再漂亮的图表都会被一句「这个数到底什么单位」给问住。我第一次交付碳排大屏时就是把一个累计值当成了当年值画进趋势图上线第一天被现场看出数据对不上之后所有图表的 tooltip 和副标题都强制带口径。这也是我做碳排大屏最重要的一个习惯先让人信再让人看。希望这套流程能帮你少走一轮弯路把 Python、数据和图表真正串成一块能上台面的大屏。本文还有配套的精品资源点击获取
返回列表