Flask+Plotly渲染异常排查:代码显示而非图表加载问题
问题排查:Flask-RESTful中Plotly图表无法渲染,仅显示JS代码
我用Python+Flask+Plotly编写了两段代码,第一段基于Flask-RESTful实现的接口无法渲染图表,页面仅显示JS代码;但第二段用普通Flask路由实现的代码能正常加载图表,请协助排查第一段代码的问题。
第一段(无法正常渲染的代码)
import pandas as pd import plotly.graph_objects as go from flask import Flask, request, render_template_string from flask_restful import Api, Resource, reqparse import json app = Flask(__name__) api = Api(app) def create_scatter_trace(x, y, name, color, dash_style=None): return go.Scatter( x=x, y=y, mode="lines", name=name, line=dict(shape="spline", color=color, width=2, dash=dash_style), hovertemplate="%{y}", showlegend=False ) def linechart_graphs(df): fig_occ = go.Figure() fig_occ.add_trace(create_scatter_trace(df['Future Months'], df["future_data"], "future_data", "red")) return fig_occ class LineChartResource(Resource): def get(self): parser = reqparse.RequestParser() parser.add_argument('country', type=str, help='Invalid country', required=False) parser.add_argument('state', type=str, help='Invalid state', required=False) args = parser.parse_args() listing_id = args['country'] pms = args['state'] today = pd.Timestamp.today() future_months = [today + pd.DateOffset(days=i * 30) for i in range(12)] future_data = [50 + i for i in range(12)] data = { 'Future Months': [dt.strftime("%Y-%m-%d") for dt in future_months], # Convert datetime to formatted string 'future_data': future_data, } df = pd.DataFrame(data) fig = linechart_graphs(df) chart_div = fig.to_html() # HTML content with embedded Plotly chart html_content = f""" <!DOCTYPE html> <html> <head> <title>Trends Chart</title> <!-- Include Plotly.js library --> <script src="https://cdn.plot.ly/plotly-latest.min.js"></script> </head> <body> <h1>Trends Chart</h1> <div> {chart_div} </div> </body> </html> """ return render_template_string(html_content) api.add_resource(LineChartResource, '/line_chart') if __name__ == '__main__': app.run()
第二段(正常渲染的代码)
import pandas as pd import plotly.graph_objects as go from flask import Flask, request, render_template_string from flask_restful import Api, Resource, reqparse app = Flask(__name__) def create_scatter_trace(x, y, name, color, dash_style=None): return go.Scatter( x=x, y=y, mode="lines", name=name, line=dict(shape="spline", color=color, width=2, dash=dash_style), hovertemplate="%{y}", showlegend=False ) def linechart_graphs(df): fig_occ = go.Figure() fig_occ.add_trace(create_scatter_trace(df['Future Months'], df["future_data"], "future_data", "red")) return fig_occ @app.route('/') def line_chart_page(): today = pd.Timestamp.today() future_months = [today + pd.DateOffset(days=i * 30) for i in range(12)] future_data = [50 + i for i in range(12)] data = { 'Future Months': [dt.strftime("%Y-%m-%d") for dt in future_months], # Convert datetime to formatted string 'future_data': future_data, } df = pd.DataFrame(data) # Create the line chart figure using the custom layout fig = linechart_graphs(df) # Convert the Plotly figure to an HTML div element chart_div = fig.to_html(full_html=False) # HTML content with embedded Plotly chart html_content = f""" <!DOCTYPE html> <html> <head> <title>Trends Chart</title> <!-- Include Plotly.js library --> <script src="https://cdn.plot.ly/plotly-latest.min.js"></script> </head> <body> <h1>Trends Chart</h1> <div> {chart_div} </div> </body> </html> """ return render_template_string(html_content) if __name__ == '__main__': app.run()
问题根源分析
两段代码的核心差异导致了渲染结果不同:
fig.to_html()参数差异- 第一段使用默认的
fig.to_html(),会生成完整的HTML文档(包含<html>、<head>等顶层标签),导致自定义HTML模板中嵌套了完整HTML结构,浏览器解析时出现冲突,JS无法执行。 - 第二段使用
fig.to_html(full_html=False),仅生成图表所需的<div>和JS代码片段,能正确嵌入自定义模板。
- 第一段使用默认的
Flask-RESTful的响应处理特性
Flask-RESTful的Resource默认会尝试将返回值序列化为JSON,导致HTML中的特殊字符(如<、>)被转义为实体字符(<、>),最终页面显示的是转义后的文本而非可执行的JS代码。
普通Flask路由则直接返回HTML字符串,不会做额外转义。
修复方案
对第一段代码做两处关键修改:
- 修改
fig.to_html()调用,添加full_html=False参数:chart_div = fig.to_html(full_html=False) - 在返回响应时指定内容类型为
text/html,避免JSON序列化转义:return render_template_string(html_content), 200, {'Content-Type': 'text/html'}
内容的提问来源于stack exchange,提问作者r ram
相关产品推荐
相关产品推荐

