赞
踩
目录
Flask使用Jinja2作为其模板引擎,这是一个功能强大、灵活且易于使用的模板系统。在数据可视化中,Flask模板系统允许我们将后端的数据处理逻辑与前端的展示逻辑分离,从而实现更清晰的代码结构和更高的可维护性。
Jinja2使用{{ }}
来输出变量,{% %}
来编写控制结构。例如:
<h1>{{ title }}</h1> <ul> {% for item in items %} <li>{{ item }}</li> {% endfor %} </ul>
在Flask应用中,我们使用render_template
函数来渲染模板:
- from flask import Flask, render_template
-
- app = Flask(__name__)
-
- @app.route('/')
- def index():
- data = {
- 'title': '数据可视化示例',
- 'items': ['图表1', '图表2', '图表3']
- }
- return render_template('index.html', **data)
首先,我们来看如何使用Flask模板生成静态图表。我们将使用Matplotlib库来生成图表,然后将其嵌入到Flask模板中。
- import io
- import base64
- import matplotlib.pyplot as plt
- from flask import Flask, render_template
-
- app = Flask(__name__)
-
- def generate_plot():
- plt.figure(figsize=(10, 6))
- plt.plot([1, 2, 3, 4], [1, 4, 2, 3])
- plt.title('示例折线图')
- plt.xlabel('X轴')
- plt.ylabel('Y轴')
-
- img = io.BytesIO()
- plt.savefig(img, format='png')
- img.seek(0)
- plot_url = base64.b64encode(img.getvalue()).decode()
- return plot_url
-
- @app.route('/static-plot')
- def static_plot():
- plot_url = generate_plot()
- return render_template('static_plot.html', plot_url=plot_url)

对应的static_plot.html
模板:
- <!DOCTYPE html>
- <html>
- <head>
- <title>静态图表示例</title>
- </head>
- <body>
- <h1>Matplotlib生成的静态图表</h1>
- <img src="data:image/png;base64,{{ plot_url }}">
- </body>
- </html>
这个例子展示了如何在Flask后端生成图表,然后将其作为base64编码的图像传递给前端模板。这种方法适用于简单的、不需要交互的图表。
接下来,我们将探讨如何使用Charts.js库来创建交互式图表。Charts.js是一个流行的JavaScript图表库,它提供了丰富的图表类型和交互选项。
- from flask import Flask, render_template, jsonify
- import random
-
- app = Flask(__name__)
-
- @app.route('/bar-chart')
- def bar_chart():
- labels = ['红色', '蓝色', '黄色', '绿色', '紫色']
- values = [random.randint(10, 100) for _ in range(5)]
- return render_template('bar_chart.html', labels=labels, values=values)
-
- @app.route('/update-bar-data')
- def update_bar_data():
- values = [random.randint(10, 100) for _ in range(5)]
- return jsonify(values=values)
对应的bar_chart.html
模板:
- <!DOCTYPE html>
- <html>
- <head>
- <title>交互式柱状图</title>
- <script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
- <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
- </head>
- <body>
- <canvas id="barChart" width="400" height="200"></canvas>
- <button onclick="updateChart()">更新数据</button>
-
- <script>
- var ctx = document.getElementById('barChart').getContext('2d');
- var myChart = new Chart(ctx, {
- type: 'bar',
- data: {
- labels: {{ labels | tojson }},
- datasets: [{
- label: '颜色数量',
- data: {{ values | tojson }},
- backgroundColor: [
- 'rgba(255, 99, 132, 0.6)',
- 'rgba(54, 162, 235, 0.6)',
- 'rgba(255, 206, 86, 0.6)',
- 'rgba(75, 192, 192, 0.6)',
- 'rgba(153, 102, 255, 0.6)'
- ]
- }]
- },
- options: {
- responsive: true,
- scales: {
- y: {
- beginAtZero: true
- }
- }
- }
- });
-
- function updateChart() {
- $.getJSON('/update-bar-data', function(data) {
- myChart.data.datasets[0].data = data.values;
- myChart.update();
- });
- }
- </script>
- </body>
- </html>

这个例子展示了如何创建一个交互式的柱状图,并通过AJAX请求动态更新数据。用户可以点击"更新数据"按钮来刷新图表,而无需重新加载整个页面。
接下来,我们来创建一个折线图,展示一段时间内的数据趋势:
- from flask import Flask, render_template, jsonify
- import random
- from datetime import datetime, timedelta
-
- app = Flask(__name__)
-
- def generate_time_series_data(days=30):
- end_date = datetime.now()
- start_date = end_date - timedelta(days=days)
- dates = [(start_date + timedelta(days=i)).strftime('%Y-%m-%d') for i in range(days)]
- values = [random.randint(50, 200) for _ in range(days)]
- return dates, values
-
- @app.route('/line-chart')
- def line_chart():
- dates, values = generate_time_series_data()
- return render_template('line_chart.html', dates=dates, values=values)
-
- @app.route('/update-line-data')
- def update_line_data():
- _, values = generate_time_series_data()
- return jsonify(values=values)

对应的line_chart.html
模板:
- <!DOCTYPE html>
- <html>
- <head>
- <title>交互式折线图</title>
- <script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
- <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
- </head>
- <body>
- <canvas id="lineChart" width="800" height="400"></canvas>
- <button onclick="updateChart()">更新数据</button>
-
- <script>
- var ctx = document.getElementById('lineChart').getContext('2d');
- var myChart = new Chart(ctx, {
- type: 'line',
- data: {
- labels: {{ dates | tojson }},
- datasets: [{
- label: '每日数据',
- data: {{ values | tojson }},
- borderColor: 'rgb(75, 192, 192)',
- tension: 0.1
- }]
- },
- options: {
- responsive: true,
- scales: {
- x: {
- type: 'time',
- time: {
- unit: 'day'
- }
- },
- y: {
- beginAtZero: true
- }
- }
- }
- });
-
- function updateChart() {
- $.getJSON('/update-line-data', function(data) {
- myChart.data.datasets[0].data = data.values;
- myChart.update();
- });
- }
- </script>
- </body>
- </html>

这个折线图示例展示了如何处理时间序列数据,并使用Charts.js的时间轴功能来正确显示日期。
Plotly是另一个强大的JavaScript可视化库,它提供了更多的交互性和更复杂的图表类型。让我们使用Plotly创建一个散点图和热力图。
- import plotly
- import plotly.graph_objs as go
- import pandas as pd
- import json
-
- app = Flask(__name__)
-
- @app.route('/scatter-plot')
- def scatter_plot():
- # 假设我们有一个包含身高、体重和年龄数据的DataFrame
- df = pd.DataFrame({
- 'height': [165, 170, 175, 180, 185, 190],
- 'weight': [60, 65, 70, 75, 80, 85],
- 'age': [25, 30, 35, 40, 45, 50]
- })
-
- trace = go.Scatter(
- x=df['height'],
- y=df['weight'],
- mode='markers',
- marker=dict(
- size=df['age'],
- color=df['age'],
- colorscale='Viridis',
- showscale=True
- ),
- text=df['age'],
- hoverinfo='text'
- )
-
- layout = go.Layout(
- title='身高与体重的关系(气泡大小表示年龄)',
- xaxis=dict(title='身高 (cm)'),
- yaxis=dict(title='体重 (kg)')
- )
-
- fig = go.Figure(data=[trace], layout=layout)
- graphJSON = json.dumps(fig, cls=plotly.utils.PlotlyJSONEncoder)
- return render_template('scatter_plot.html', graphJSON=graphJSON)

对应的scatter_plot.html
模板:
- <!DOCTYPE html>
- <html>
- <head>
- <title>Plotly散点图示例</title>
- <script src="https://cdn.plot.ly/plotly-latest.min.js"></script>
- </head>
- <body>
- <div id="chart" style="width:100%;height:600px;"></div>
- <script>
- var graphs = {{graphJSON | safe}};
- Plotly.newPlot('chart', graphs);
- </script>
- </body>
- </html>
这个散点图展示了如何使用Plotly创建多维数据可视化,其中点的位置表示身高和体重,而点的大小和颜色表示年龄。
接下来,让我们创建一个热力图来展示某个城市一周内每小时的温度变化:
- import plotly
- import plotly.graph_objs as go
- import pandas as pd
- import numpy as np
- import json
-
- app = Flask(__name__)
-
- @app.route('/heatmap')
- def heatmap():
- # 生成模拟数据
- hours = 24
- days = 7
- z = np.random.randint(10, 30, size=(days, hours))
-
- data = go.Heatmap(
- z=z,
- x=[f'{i}:00' for i in range(24)],
- y=['周一', '周二', '周三', '周四', '周五', '周六', '周日'],
- colorscale='Viridis'
- )
-
- layout = go.Layout(
- title='一周温度变化热力图',
- xaxis=dict(title='小时'),
- yaxis=dict(title='星期')
- )
-
- fig = go.Figure(data=[data], layout=layout)
- graphJSON = json.dumps(fig, cls=plotly.utils.PlotlyJSONEncoder)
- return render_template('heatmap.html', graphJSON=graphJSON)

对应的heatmap.html
模板:
- <!DOCTYPE html>
- <html>
- <head>
- <title>Plotly热力图示例</title>
- <script src="https://cdn.plot.ly/plotly-latest.min.js"></script>
- </head>
- <body>
- <div id="chart" style="width:100%;height:600px;"></div>
- <script>
- var graphs = {{graphJSON | safe}};
- Plotly.newPlot('chart', graphs);
- </script>
- </body>
- </html>
这个热力图展示了如何使用Plotly创建复杂的二维数据可视化,非常适合展示时间序列或矩阵形式的数据。
在实际应用中,我们经常需要在一个页面上展示多个相关的图表。下面我们将创建一个仪表板,同时显示多个图表:
- import plotly
- import plotly.graph_objs as go
- import pandas as pd
- import numpy as np
- import json
-
- app = Flask(__name__)
-
- def create_bar_chart():
- categories = ['A', 'B', 'C', 'D', 'E']
- values = np.random.randint(10, 100, size=5)
-
- data = go.Bar(x=categories, y=values)
- layout = go.Layout(title='类别分布')
-
- return go.Figure(data=[data], layout=layout)
-
- def create_pie_chart():
- labels = ['产品1', '产品2', '产品3', '产品4']
- values = np.random.randint(100, 1000, size=4)
-
- data = go.Pie(labels=labels, values=values)
- layout = go.Layout(title='产品销售占比')
-
- return go.Figure(data=[data], layout=layout)
-
- def create_line_chart():
- dates = pd.date_range(start='2023-01-01', end='2023-12-31', freq='M')
- values = np.cumsum(np.random.randn(12))
-
- data = go.Scatter(x=dates, y=values, mode='lines+markers')
- layout = go.Layout(title='月度趋势')
-
- return go.Figure(data=[data], layout=layout)
-
- @app.route('/dashboard')
- def dashboard():
- bar_chart = create_bar_chart()
- pie_chart = create_pie_chart()
- line_chart = create_line_chart()
-
- charts = {
- 'bar': json.dumps(bar_chart, cls=plotly.utils.PlotlyJSONEncoder),
- 'pie': json.dumps(pie_chart, cls=plotly.utils.PlotlyJSONEncoder),
- 'line': json.dumps(line_chart, cls=plotly.utils.PlotlyJSONEncoder)
- }
-
- return render_template('dashboard.html', charts=charts)

对应的dashboard.html
模板:
- <!DOCTYPE html>
- <html>
- <head>
- <title>数据可视化仪表板</title>
- <script src="https://cdn.plot.ly/plotly-latest.min.js"></script>
- <style>
- .chart-container {
- width: 45%;
- height: 400px;
- display: inline-block;
- margin: 10px;
- }
- </style>
- </head>
- <body>
- <h1>数据可视化仪表板</h1>
- <div class="chart-container" id="bar-chart"></div>
- <div class="chart-container" id="pie-chart"></div>
- <div class="chart-container" id="line-chart"></div>
-
- <script>
- var barChart = JSON.parse({{ charts.bar | tojson | safe }});
- var pieChart = JSON.parse({{ charts.pie | tojson | safe }});
- var lineChart = JSON.parse({{ charts.line | tojson | safe }});
-
- Plotly.newPlot('bar-chart', barChart.data, barChart.layout);
- Plotly.newPlot('pie-chart', pieChart.data, pieChart.layout);
- Plotly.newPlot('line-chart', lineChart.data, lineChart.layout);
- </script>
- </body>
- </html>

这个仪表板示例展示了如何在一个页面中组合多个图表,为用户提供全面的数据概览。
在实际应用中,我们通常需要处理大量实时更新的数据。下面我们将创建一个股票价格实时监控系统,展示如何使用Flask和WebSocket来实现实时数据可视化。
首先,安装必要的库:
pip install flask-socketio
然后,创建以下Python文件:
- from flask import Flask, render_template
- from flask_socketio import SocketIO
- import json
- import random
- import time
- from threading import Thread
-
- app = Flask(__name__)
- app.config['SECRET_KEY'] = 'secret!'
- socketio = SocketIO(app)
-
- def generate_stock_data():
- stocks = ['AAPL', 'GOOGL', 'MSFT', 'AMZN']
- while True:
- data = {stock: random.randint(100, 200) for stock in stocks}
- socketio.emit('stock_update', json.dumps(data))
- time.sleep(1)
-
- @app.route('/')
- def index():
- return render_template('stock_monitor.html')
-
- if __name__ == '__main__':
- Thread(target=generate_stock_data).start()
- socketio.run(app, debug=True)

创建对应的stock_monitor.html
模板:
- <!DOCTYPE html>
- <html>
- <head>
- <title>实时股票价格监控</title>
- <script src="https://cdn.plot.ly/plotly-latest.min.js"></script>
- <script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/4.0.1/socket.io.js"></script>
- </head>
- <body>
- <div id="chart" style="width:100%;height:600px;"></div>
-
- <script>
- var socket = io();
- var time = new Date();
-
- var trace1 = {x: [time], y: [0], name: 'AAPL', mode: 'lines+markers'};
- var trace2 = {x: [time], y: [0], name: 'GOOGL', mode: 'lines+markers'};
- var trace3 = {x: [time], y: [0], name: 'MSFT', mode: 'lines+markers'};
- var trace4 = {x: [time], y: [0], name: 'AMZN', mode: 'lines+markers'};
-
- var data = [trace1, trace2, trace3, trace4];
- var layout = {title: '实时股票价格', xaxis: {title: '时间'}, yaxis: {title: '价格'}};
-
- Plotly.newPlot('chart', data, layout);
-
- socket.on('stock_update', function(msg) {
- var data = JSON.parse(msg);
- var time = new Date();
-
- var update = {
- x: [[time], [time], [time], [time]],
- y: [[data.AAPL], [data.GOOGL], [data.MSFT], [data.AMZN]]
- }
-
- Plotly.extendTraces('chart', update, [0, 1, 2, 3]);
-
- if(time - data[0].x[0] > 30000) {
- Plotly.relayout('chart', {
- xaxis: {
- range: [time - 30000, time]
- }
- });
- }
- });
- </script>
- </body>
- </html>

这个示例展示了如何使用Flask-SocketIO创建一个实时更新的股票价格监控系统。服务器每秒生成新的股票价格数据并通过WebSocket发送给客户端,客户端接收数据后实时更新图表。
在实际应用中,我们经常需要对原始数据进行处理后再进行可视化。下面我们将创建一个简单的数据分析和可视化系统,展示如何在Flask中结合数据处理和可视化。
- from flask import Flask, render_template, request
- import pandas as pd
- import plotly
- import plotly.express as px
- import json
-
- app = Flask(__name__)
-
- @app.route('/', methods=['GET', 'POST'])
- def index():
- if request.method == 'POST':
- file = request.files['file']
- if file:
- df = pd.read_csv(file)
-
- # 数据处理
- df['Total'] = df['Quantity'] * df['UnitPrice']
- top_countries = df.groupby('Country')['Total'].sum().nlargest(10).index.tolist()
- df_top = df[df['Country'].isin(top_countries)]
-
- # 创建图表
- fig1 = px.bar(df_top.groupby('Country')['Total'].sum().reset_index(),
- x='Country', y='Total', title='Top 10 Countries by Sales')
-
- fig2 = px.scatter(df_top, x='Quantity', y='UnitPrice', color='Country',
- size='Total', hover_data=['Description'],
- title='Quantity vs Unit Price by Country')
-
- # 将图表转换为JSON
- chart1JSON = json.dumps(fig1, cls=plotly.utils.PlotlyJSONEncoder)
- chart2JSON = json.dumps(fig2, cls=plotly.utils.PlotlyJSONEncoder)
-
- return render_template('analysis.html', chart1JSON=chart1JSON, chart2JSON=chart2JSON)
-
- return render_template('upload.html')

创建upload.html
模板:
- <!DOCTYPE html>
- <html>
- <head>
- <title>数据上传</title>
- </head>
- <body>
- <h1>上传CSV文件进行分析</h1>
- <form method="post" enctype="multipart/form-data">
- <input type="file" name="file" accept=".csv">
- <input type="submit" value="上传并分析">
- </form>
- </body>
- </html>
创建analysis.html
模板:
- <!DOCTYPE html>
- <html>
- <head>
- <title>数据分析结果</title>
- <script src="https://cdn.plot.ly/plotly-latest.min.js"></script>
- </head>
- <body>
- <h1>数据分析结果</h1>
- <div id="chart1" style="width:100%;height:500px;"></div>
- <div id="chart2" style="width:100%;height:500px;"></div>
-
- <script>
- var chart1 = JSON.parse({{ chart1JSON | tojson | safe }});
- var chart2 = JSON.parse({{ chart2JSON | tojson | safe }});
-
- Plotly.newPlot('chart1', chart1.data, chart1.layout);
- Plotly.newPlot('chart2', chart2.data, chart2.layout);
- </script>
- </body>
- </html>

这个示例展示了如何创建一个简单的数据分析和可视化系统。用户可以上传CSV文件,系统会对数据进行简单的处理,然后创建两个图表:一个柱状图显示销售额最高的10个国家,一个散点图显示数量与单价的关系。
最后,让我们探索如何将机器学习模型的结果与数据可视化结合起来。我们将创建一个简单的聚类分析可视化系统。
首先,安装必要的库:
pip install scikit-learn
然后,创建以下Python文件:
- from flask import Flask, render_template, request
- import pandas as pd
- import numpy as np
- from sklearn.cluster import KMeans
- from sklearn.preprocessing import StandardScaler
- import plotly.express as px
- import json
-
- app = Flask(__name__)
-
- @app.route('/', methods=['GET', 'POST'])
- def index():
- if request.method == 'POST':
- file = request.files['file']
- if file:
- df = pd.read_csv(file)
-
- # 数据预处理
- features = ['Annual Income (k$)', 'Spending Score (1-100)']
- X = df[features]
- scaler = StandardScaler()
- X_scaled = scaler.fit_transform(X)
-
- # 聚类分析
- kmeans = KMeans(n_clusters=5, random_state=42)
- df['Cluster'] = kmeans.fit_predict(X_scaled)
-
- # 创建图表
- fig = px.scatter(df, x='Annual Income (k$)', y='Spending Score (1-100)',
- color='Cluster', hover_data=['Age', 'Gender'],
- title='Customer Segmentation')
-
- # 将图表转换为JSON
- chartJSON = json.dumps(fig, cls=plotly.utils.PlotlyJSONEncoder)
-
- return render_template('cluster_result.html', chartJSON=chartJSON)
-
- return render_template('upload_for_clustering.html')

创建upload_for_clustering.html
模板:
- <!DOCTYPE html>
- <html>
- <head>
- <title>上传数据进行聚类分析</title>
- </head>
- <body>
- <h1>上传CSV文件进行聚类分析</h1>
- <form method="post" enctype="multipart/form-data">
- <input type="file" name="file" accept=".csv">
- <input type="submit" value="上传并分析">
- </form>
- </body>
- </html>
创建cluster_result.html
模板:
- <!DOCTYPE html>
- <html>
- <head>
- <title>聚类分析结果</title>
- <script src="https://cdn.plot.ly/plotly-latest.min.js"></script>
- </head>
- <body>
- <h1>聚类分析结果</h1>
- <div id="chart" style="width:100%;height:600px;"></div>
-
- <script>
- var chart = JSON.parse({{ chartJSON | tojson | safe }});
- Plotly.newPlot('chart', chart.data, chart.layout);
- </script>
- </body>
- </html>

这个示例展示了如何创建一个简单的聚类分析可视化系统。用户上传包含客户数据的CSV文件后,系统会使用K-means算法进行聚类分析,然后创建一个散点图来可视化聚类结果。
通过这些详细的示例,我们展示了Flask模板在数据可视化中的多种应用场景:
基础的静态图表生成
使用Charts.js创建交互式图表
使用Plotly创建高级交互式可视化
创建包含多个图表的仪表板
实现实时数据的动态可视化
结合数据处理和可视化
将机器学习模型的结果可视化
Flask的灵活性使得它能够适应各种数据可视化需求,从简单的静态图表到复杂的交互式可视化,再到实时数据的动态展示。通过合理使用模板系统,我们可以将后端的数据处理逻辑与前端的展示逻辑分离,提高代码的可维护性和可扩展性。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。