news 2026/2/16 4:45:18

Python用Flask后端解析Excel图表,Vue3+ECharts前端动态还原(附全套代码)

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Python用Flask后端解析Excel图表,Vue3+ECharts前端动态还原(附全套代码)

以下是完整的Flask + Vue 3 前端模板方案,实现上传 Excel 文件(不再用链接),后端解析chart1.xml,返回结构化数据,前端用 ECharts 渲染图表。

项目结构

project/ ├── app.py ├── templates/ │ └── index.html

1. 后端:app.py

importxml.etree.ElementTreeasETimportiofromzipfileimportZipFile,BadZipFilefromflaskimportFlask,render_template,request,jsonifyfromflask_corsimportCORS# 可选,如果有跨域需求app=Flask(__name__)CORS(app)# 允许跨域(同域其实不需要,但留着保险)defparse_chart_from_bytes(file_data):res={}result={}try:archive=ZipFile(io.BytesIO(file_data))chart_data=archive.read('xl/charts/chart1.xml')res['code']=200res['msg']="获取图表信息成功"tree=ET.parse(io.BytesIO(chart_data))root=tree.getroot()ns={'c':'http://schemas.openxmlformats.org/drawingml/2006/chart','a':'http://schemas.openxmlformats.org/drawingml/2006/main'}# 图表类型type_mapping=[('pieChart','饼图','pie'),('lineChart','折线图','line'),('barChart','柱形图','bar'),('areaChart','面积图','line'),('scatterChart','散点图','scatter'),('radarChart','雷达图','radar'),]chart_type_cn='其它'echarts_type='line'is_area=Falsefortag,cn,enintype_mapping:ifroot.find(f'.//c:{tag}',ns)isnotNone:chart_type_cn=cn echarts_type=enifcn=='面积图':is_area=Truebreakresult['chart_type_cn']=chart_type_cn result['echarts_type']=echarts_type result['is_area']=is_area# 标题title_text=""title_elem=root.find('.//c:title/c:tx/c:rich',ns)iftitle_elemisnotNone:fortintitle_elem.iterfind('.//a:t',ns):ift.text:title_text+=t.text result['title']=title_text.strip()or"无标题"# 系列数据series_list=[]ser_elements=root.findall('.//c:ser',ns)foridx,serinenumerate(ser_elements):# 系列名称name_elem=ser.find('c:tx/c:v',ns)name=name_elem.textifname_elemisnotNoneelsef"系列{idx+1}"# 类别(X轴)cat_vs=ser.findall('c:cat//c:pt/c:v',ns)categories=[v.textforvincat_vsifv.textisnotNone]# 数值(Y轴)val_vs=ser.findall('c:val//c:pt/c:v',ns)values=[]forvinval_vs:ifv.text:try:values.append(float(v.text))exceptValueError:values.append(v.text)series_list.append({"name":name,"categories":categories,"data":values})# 共享类别轴(如果每个系列都没有独立类别)ifseries_listandall(len(s['categories'])==0forsinseries_list):shared_vs=root.findall('.//c:cat//c:pt/c:v',ns)shared_cat=[v.textforvinshared_vsifv.textisnotNone]ifshared_cat:forsinseries_list:s['categories']=shared_cat# 饼图特殊处理ifchart_type_cn=="饼图"andseries_list:forsinseries_list:pie_data=[]cats=s['categories']or[f"项{i+1}"foriinrange(len(s['data']))]fori,valinenumerate(s['data']):name=cats[i]ifi<len(cats)elsef"项{i+1}"value=valifisinstance(val,(int,float))else0pie_data.append({"name":name,"value":value})s['data']=pie_data# 最终类别轴(非饼图)ifchart_type_cn!="饼图"andseries_listandseries_list[0]['categories']:result['categories']=series_list[0]['categories']else:result['categories']=[]# 系列(只保留 name 和 data)result['series']=[{"name":s["name"],"data":s["data"]}forsinseries_list]res['data']=resultexceptBadZipFile:res['code']=404res['msg']="无效的Excel文件"exceptKeyError:res['code']=404res['msg']="未找到图表信息(无chart1.xml)"exceptExceptionase:res['code']=500res['msg']=f"解析失败:{str(e)}"returnres@app.route('/')defindex():returnrender_template('index.html')@app.route('/api/upload_chart',methods=['POST'])defupload_chart():if'file'notinrequest.files:returnjsonify({"code":400,"msg":"没有上传文件"})file=request.files['file']iffile.filename==''ornotfile.filename.lower().endswith('.xlsx'):returnjsonify({"code":400,"msg":"请上传 .xlsx 文件"})file_data=file.read()returnjsonify(parse_chart_from_bytes(file_data))if__name__=='__main__':app.run(host='127.0.0.1',port=5000,debug=True)

2. 前端模板:templates/index.html

<!DOCTYPEhtml><htmllang="zh-CN"><head><metacharset="UTF-8"><title>上传 Excel → ECharts 渲染</title><scriptsrc="https://cdn.jsdelivr.net/npm/vue@3.4.21/dist/vue.global.prod.js"></script><scriptsrc="https://cdn.jsdelivr.net/npm/echarts@5.5.0/dist/echarts.min.js"></script><style>body{font-family:Arial,sans-serif;padding:20px;background:#f5f5f5;}.container{max-width:800px;margin:auto;background:white;padding:30px;border-radius:8px;box-shadow:0 2px 10pxrgba(0,0,0,0.1);}input[type="file"]{padding:10px;margin-bottom:15px;}button{padding:12px 24px;font-size:16px;background:#409eff;color:white;border:none;border-radius:4px;cursor:pointer;}button:hover{background:#66b1ff;}button:disabled{background:#a0cfff;cursor:not-allowed;}#chart{width:100%;height:600px;margin-top:30px;}.msg{margin:15px 0;font-weight:bold;color:#e6a23c;}</style></head><body><divid="app"class="container"><h2>上传 Excel 文件 → ECharts 渲染图表</h2><inputtype="file"accept=".xlsx"@change="onFileChange"/><button@click="uploadAndRender":disabled="!selectedFile">上传并渲染图表</button><divclass="msg">{{ message }}</div><divref="chartRef"id="chart"></div></div><script>const{createApp,ref,onMounted,nextTick}=Vue;createApp({setup(){constselectedFile=ref(null);constmessage=ref('请选择一个包含图表的 .xlsx 文件');constchartRef=ref(null);letmyChart=null;onMounted(()=>{myChart=echarts.init(chartRef.value);});constonFileChange=(e)=>{constfile=e.target.files[0];if(file&&file.name.endsWith('.xlsx')){selectedFile.value=file;message.value=`已选择文件:${file.name}`;}else{selectedFile.value=null;message.value='请上传 .xlsx 文件';}};constuploadAndRender=async()=>{if(!selectedFile.value)return;message.value='正在上传并解析...';constformData=newFormData();formData.append('file',selectedFile.value);try{constresponse=awaitfetch('/api/upload_chart',{method:'POST',body:formData});constjson=awaitresponse.json();if(json.code!==200){message.value=`错误:${json.msg}`;return;}constdata=json.data;constoption={title:{text:data.title,left:'center',textStyle:{fontSize:18}},tooltip:{trigger:data.echarts_type==='pie'?'item':'axis'},legend:{data:data.series.map(s=>s.name),top:30}};if(data.echarts_type==='pie'){option.series=data.series.map(s=>({type:'pie',name:s.name,radius:'55%',center:['50%','60%'],data:s.data,emphasis:{itemStyle:{shadowBlur:10,shadowOffsetX:0,shadowColor:'rgba(0, 0, 0, 0.5)'}}}));}elseif(data.echarts_type==='radar'){constmaxVal=Math.max(...data.series.flatMap(s=>s.data.filter(v=>typeofv==='number')),100);option.radar={indicator:data.categories.map(name=>({name,max:maxVal*1.2}))};option.series=[{type:'radar',data:data.series.map(s=>({name:s.name,value:s.data}))}];}else{option.xAxis={type:'category',data:data.categories};option.yAxis={type:'value'};option.series=data.series.map(s=>({type:data.echarts_type,name:s.name,data:s.data,areaStyle:data.is_area?{opacity:0.3}:undefined,smooth:data.echarts_type==='line'?true:false}));}awaitnextTick();myChart.setOption(option,true);message.value=`渲染成功!图表类型:${data.chart_type_cn}${data.series.length}个系列)`;}catch(err){message.value='上传或解析失败:'+err.message;console.error(err);}};return{selectedFile,message,chartRef,onFileChange,uploadAndRender};}}).mount('#app');</script></body></html>

使用方式

  1. 安装依赖:
    pipinstallflask flask-cors
  2. 把上面的文件按结构放好。
  3. 运行:
    python app.py
  4. 浏览器打开http://127.0.0.1:5000
  5. 选择一个包含图表(chart1)的.xlsx文件 → 点击“上传并渲染图表”

功能特点

  • 支持上传本地 Excel 文件解析(安全,只读内存)。
  • 支持单/多系列图表。
  • 饼图、折线、柱形、面积、散点、雷达图基本还原。
  • 前端美化了些样式和交互。

相关文章

Python 使用 openpyxl 从 URL 读取 Excel 并获取 Sheet 及单元格样式信息
Python 解析 Excel 图表(Chart)信息实战:从 xlsx 中提取标题、字体和数据

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/2/11 16:39:51

豆包真正的对手不是DeepSeek,而是千问

AI应用的终极战场正在悄然到来。根据新京报发布的最新榜单&#xff0c;截至2025年11月&#xff0c;中国AI应用月活排名前三为豆包&#xff08;2.72亿&#xff09;、DeepSeek&#xff08;1.63亿&#xff09;和夸克&#xff08;9546万&#xff09;&#xff0c;腾讯元宝以5305万位…

作者头像 李华
网站建设 2026/2/14 12:17:21

深入理解 MD5:原理、应用场景、代码实现及安全性分析

在软件开发中&#xff0c;我们经常听到 MD5 这个词。无论是用于数据库中的密码存储&#xff0c;还是下载文件时的完整性校验&#xff0c;MD5 似乎无处不在。虽然现在有了更安全的算法&#xff08;如 SHA-256、Bcrypt&#xff09;&#xff0c;但在很多非高安全级别的场景下&…

作者头像 李华
网站建设 2026/1/29 17:53:29

【新】基于SSM的高校自助洗衣系统【源码+文档+调试】

&#x1f495;&#x1f495;发布人&#xff1a; 星河码客 &#x1f495;&#x1f495;个人简介&#xff1a;混迹java圈十余年&#xff0c;精通Java、小程序、数据库等。 &#x1f495;&#x1f495;各类成品Java毕设 。javaweb&#xff0c;ssm&#xff0c;springboot等项目&…

作者头像 李华
网站建设 2026/2/13 8:06:41

阿里领导给的Java八股文,包括15条技术线,已助1900人进入大厂

为了更高的薪水跳槽无可厚非&#xff0c;但你要把握好一个度。举个例子&#xff0c;如果你每次都只是为了能增长3%的年薪&#xff0c;而频繁地换工作。当HR看到你的简历时&#xff0c;你会被认为是一个对公司没有忠心、对自己的事业没有远见的人如何准备&#xff1f;除了平时的…

作者头像 李华
网站建设 2026/2/5 23:55:37

系统思考:小行动大影响

本期的学习实验室《小行动大影响》&#xff0c;我们把注意力从“我要多做什么”&#xff0c;转向了一个更关键的问题&#xff1a;哪一个一小步&#xff0c;值得我现在就去做&#xff1f; 我们带着三个有力量的洞见开展团队学习&#xff1a;1、小行动之所以大&#xff0c;不在于…

作者头像 李华