当前位置: 首页 > news >正文

《用 python、MySQL 和 Chart.js 打造炫酷数据看板》实战案例笔记

今天,我们要构建一个数据看板系统。在这个过程中,我们会利用 MySQL 来存储数据,使用 Python 搭建后端 API,还会借助 Chart.js 在前端呈现各式各样的图表。

整个流程涵盖多个环节,首先要进行数据库表的设计,接着将数据插入到数据库中,然后搭建后端的数据接口,最后在前端通过 JavaScript 动态渲染图表,如此便形成了完整的数据看板系统。

图片

1. 安装依赖

在运行代码前,确保安装了必要的 Python 依赖:

pip install flask pymysql

2. 创建 MySQL 数据表

运行以下 SQL 代码,创建用于存储数据的 your_table 表:

CREATE TABLE kb (
    id INT AUTO_INCREMENT PRIMARY KEY,
    category VARCHAR(50),
    year INT,
    month INT,
    value INT
);

3. 数据库插入数据

运行以下 SQL 代码,插入数据:

INSERT INTO kb (category, year, month, value) VALUES ('人事', 2023, 1, 399);
INSERTINTO kb (category, year, month, value) VALUES ('人事', 2023, 1, 410);
INSERTINTO kb (category, year, month, value) VALUES ('供应链', 2023, 1, 208);
INSERTINTO kb (category, year, month, value) VALUES ('运营', 2023, 2, 291);
INSERTINTO kb (category, year, month, value) VALUES ('客服', 2023, 2, 172);
INSERTINTO kb (category, year, month, value) VALUES ('客服', 2023, 2, 199);
INSERTINTO kb (category, year, month, value) VALUES ('市场', 2023, 3, 370);
INSERTINTO kb (category, year, month, value) VALUES ('供应链', 2023, 3, 454);
INSERTINTO kb (category, year, month, value) VALUES ('市场', 2023, 3, 207);
INSERTINTO kb (category, year, month, value) VALUES ('运营', 2023, 4, 397);
INSERTINTO kb (category, year, month, value) VALUES ('研发', 2023, 4, 228);
INSERTINTO kb (category, year, month, value) VALUES ('客服', 2023, 4, 151);
INSERTINTO kb (category, year, month, value) VALUES ('供应链', 2023, 5, 373);
INSERTINTO kb (category, year, month, value) VALUES ('人事', 2023, 5, 429);
INSERTINTO kb (category, year, month, value) VALUES ('研发', 2023, 5, 307);
INSERTINTO kb (category, year, month, value) VALUES ('客服', 2023, 6, 485);
INSERTINTO kb (category, year, month, value) VALUES ('人事', 2023, 6, 419);
INSERTINTO kb (category, year, month, value) VALUES ('客服', 2023, 6, 468);
INSERTINTO kb (category, year, month, value) VALUES ('供应链', 2023, 7, 169);
INSERTINTO kb (category, year, month, value) VALUES ('市场', 2023, 7, 185);
INSERTINTO kb (category, year, month, value) VALUES ('市场', 2023, 7, 289);
INSERTINTO kb (category, year, month, value) VALUES ('市场', 2023, 8, 282);
INSERTINTO kb (category, year, month, value) VALUES ('供应链', 2023, 8, 232);
INSERTINTO kb (category, year, month, value) VALUES ('财务', 2023, 8, 339);
INSERTINTO kb (category, year, month, value) VALUES ('市场', 2023, 9, 269);
INSERTINTO kb (category, year, month, value) VALUES ('人事', 2023, 9, 274);
INSERTINTO kb (category, year, month, value) VALUES ('运营', 2023, 9, 435);
INSERTINTO kb (category, year, month, value) VALUES ('研发', 2023, 10, 463);
INSERTINTO kb (category, year, month, value) VALUES ('供应链', 2023, 10, 108);
INSERTINTO kb (category, year, month, value) VALUES ('研发', 2023, 10, 295);
INSERTINTO kb (category, year, month, value) VALUES ('研发', 2023, 11, 168);
INSERTINTO kb (category, year, month, value) VALUES ('客服', 2023, 11, 351);
INSERTINTO kb (category, year, month, value) VALUES ('人事', 2023, 11, 162);
INSERTINTO kb (category, year, month, value) VALUES ('财务', 2023, 12, 395);
INSERTINTO kb (category, year, month, value) VALUES ('供应链', 2023, 12, 428);
INSERTINTO kb (category, year, month, value) VALUES ('客服', 2023, 12, 339);
INSERTINTO kb (category, year, month, value) VALUES ('供应链', 2024, 1, 192);
INSERTINTO kb (category, year, month, value) VALUES ('财务', 2024, 1, 156);
INSERTINTO kb (category, year, month, value) VALUES ('销售', 2024, 1, 130);
INSERTINTO kb (category, year, month, value) VALUES ('研发', 2024, 2, 442);
INSERTINTO kb (category, year, month, value) VALUES ('供应链', 2024, 2, 149);
INSERTINTO kb (category, year, month, value) VALUES ('供应链', 2024, 2, 460);
INSERTINTO kb (category, year, month, value) VALUES ('销售', 2024, 3, 293);
INSERTINTO kb (category, year, month, value) VALUES ('市场', 2024, 3, 228);
INSERTINTO kb (category, year, month, value) VALUES ('人事', 2024, 3, 231);
INSERTINTO kb (category, year, month, value) VALUES ('市场', 2024, 4, 288);
INSERTINTO kb (category, year, month, value) VALUES ('研发', 2024, 4, 242);
INSERTINTO kb (category, year, month, value) VALUES ('销售', 2024, 4, 205);
INSERTINTO kb (category, year, month, value) VALUES ('销售', 2024, 5, 491);
INSERTINTO kb (category, year, month, value) VALUES ('市场', 2024, 5, 144);
INSERTINTO kb (category, year, month, value) VALUES ('财务', 2024, 5, 255);
INSERTINTO kb (category, year, month, value) VALUES ('客服', 2024, 6, 128);
INSERTINTO kb (category, year, month, value) VALUES ('市场', 2024, 6, 439);
INSERTINTO kb (category, year, month, value) VALUES ('销售', 2024, 6, 177);
INSERTINTO kb (category, year, month, value) VALUES ('运营', 2024, 7, 486);
INSERTINTO kb (category, year, month, value) VALUES ('财务', 2024, 7, 411);
INSERTINTO kb (category, year, month, value) VALUES ('人事', 2024, 7, 338);
INSERTINTO kb (category, year, month, value) VALUES ('销售', 2024, 8, 456);
INSERTINTO kb (category, year, month, value) VALUES ('人事', 2024, 8, 93);
INSERTINTO kb (category, year, month, value) VALUES ('供应链', 2024, 8, 63);
INSERTINTO kb (category, year, month, value) VALUES ('客服', 2024, 9, 149);
INSERTINTO kb (category, year, month, value) VALUES ('销售', 2024, 9, 248);
INSERTINTO kb (category, year, month, value) VALUES ('市场', 2024, 9, 158);
INSERTINTO kb (category, year, month, value) VALUES ('运营', 2024, 10, 255);
INSERTINTO kb (category, year, month, value) VALUES ('运营', 2024, 10, 493);
INSERTINTO kb (category, year, month, value) VALUES ('供应链', 2024, 10, 234);
INSERTINTO kb (category, year, month, value) VALUES ('市场', 2024, 11, 383);
INSERTINTO kb (category, year, month, value) VALUES ('销售', 2024, 11, 128);
INSERTINTO kb (category, year, month, value) VALUES ('销售', 2024, 11, 116);
INSERTINTO kb (category, year, month, value) VALUES ('客服', 2024, 12, 438);
INSERTINTO kb (category, year, month, value) VALUES ('销售', 2024, 12, 449);
INSERTINTO kb (category, year, month, value) VALUES ('客服', 2024, 12, 426);
INSERTINTO kb (category, year, month, value) VALUES ('销售', 2025, 1, 171);
INSERTINTO kb (category, year, month, value) VALUES ('运营', 2025, 1, 270);
INSERTINTO kb (category, year, month, value) VALUES ('研发', 2025, 1, 350);
INSERTINTO kb (category, year, month, value) VALUES ('市场', 2025, 2, 351);
INSERTINTO kb (category, year, month, value) VALUES ('供应链', 2025, 2, 260);
INSERTINTO kb (category, year, month, value) VALUES ('供应链', 2025, 2, 186);
INSERTINTO kb (category, year, month, value) VALUES ('研发', 2025, 3, 51);
INSERTINTO kb (category, year, month, value) VALUES ('人事', 2025, 3, 410);
INSERTINTO kb (category, year, month, value) VALUES ('运营', 2025, 3, 294);
INSERTINTO kb (category, year, month, value) VALUES ('销售', 2025, 4, 495);
INSERTINTO kb (category, year, month, value) VALUES ('人事', 2025, 4, 436);
INSERTINTO kb (category, year, month, value) VALUES ('人事', 2025, 4, 363);
INSERTINTO kb (category, year, month, value) VALUES ('销售', 2025, 5, 406);
INSERTINTO kb (category, year, month, value) VALUES ('市场', 2025, 5, 149);
INSERTINTO kb (category, year, month, value) VALUES ('销售', 2025, 5, 329);
INSERTINTO kb (category, year, month, value) VALUES ('市场', 2025, 6, 187);
INSERTINTO kb (category, year, month, value) VALUES ('研发', 2025, 6, 490);
INSERTINTO kb (category, year, month, value) VALUES ('人事', 2025, 6, 471);
INSERTINTO kb (category, year, month, value) VALUES ('财务', 2025, 7, 387);
INSERTINTO kb (category, year, month, value) VALUES ('人事', 2025, 7, 481);
INSERTINTO kb (category, year, month, value) VALUES ('人事', 2025, 7, 249);
INSERTINTO kb (category, year, month, value) VALUES ('人事', 2025, 8, 177);
INSERTINTO kb (category, year, month, value) VALUES ('市场', 2025, 8, 160);
INSERTINTO kb (category, year, month, value) VALUES ('客服', 2025, 8, 423);
INSERTINTO kb (category, year, month, value) VALUES ('销售', 2025, 9, 111);
INSERTINTO kb (category, year, month, value) VALUES ('客服', 2025, 9, 131);
INSERTINTO kb (category, year, month, value) VALUES ('人事', 2025, 9, 426);
INSERTINTO kb (category, year, month, value) VALUES ('市场', 2025, 10, 448);
INSERTINTO kb (category, year, month, value) VALUES ('研发', 2025, 10, 317);
INSERTINTO kb (category, year, month, value) VALUES ('运营', 2025, 10, 58);
INSERTINTO kb (category, year, month, value) VALUES ('运营', 2025, 11, 311);
INSERTINTO kb (category, year, month, value) VALUES ('客服', 2025, 11, 343);
INSERTINTO kb (category, year, month, value) VALUES ('运营', 2025, 11, 284);
INSERTINTO kb (category, year, month, value) VALUES ('研发', 2025, 12, 312);
INSERTINTO kb (category, year, month, value) VALUES ('财务', 2025, 12, 95);
INSERTINTO kb (category, year, month, value) VALUES ('客服', 2025, 12, 400);

4. python后端(server.py)

from flask import Flask, jsonify, render_template
import pymysql.cursors

app = Flask(__name__)

# 连接 MySQL 数据库
def get_db_connection():
    return pymysql.connect(
        host="localhost",
        user="root",  # 修改为你的数据库用户名
        password="root",  # 修改为你的数据库密码
        database="demo2",  # 修改为你的数据库名称
        port=3306,
        cursorclass=pymysql.cursors.DictCursor
    )




# API:获取数据
@app.route("/api/data")
def get_data():
    connection = get_db_connection()
    with connection.cursor() as cursor:
        cursor.execute("SELECT year, month, category, value FROM kb ORDER BY year, month")
        data = cursor.fetchall()
    connection.close()
    return jsonify(data)

# 前端页面
@app.route("/")
def index():
    return render_template("index.html")

if __name__ == "__main__":
    app.run(debug=True)

5. 前端页面(templates/index.html)

在 templates/ 目录下创建 index.html 文件:

<!DOCTYPE html>
<html lang="zh">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>数据看板</title>
    <script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
    <style>
        body {
            font-family: 'Arial', sans-serif;
            background: linear-gradient(to right, #141e30, #243b55);
            color: white;
            text-align: center;
            padding: 20px;
        }
        h2 {
            font-size: 2rem;
            margin-bottom: 20px;
        }
        .chart-container {
            display: grid;
            grid-template-columns: 1fr 1fr;
            gap: 20px;
            justify-items: center;
            padding: 20px;
        }
        .chart-box {
            width: 1000px;      /* 根据需求可继续调大或调小 */
            height: 500px;     /* 根据需求可继续调大或调小 */
            background: rgba(255, 255, 255, 0.1);
            padding: 20px;
            border-radius: 15px;
            box-shadow: 0px 0px 15px rgba(255, 255, 255, 0.3);
            transition: transform 0.3s;
            display: flex;
            align-items: center;
            justify-content: center;
        }
        .chart-box:hover {
            transform: scale(1.05);
        }
        canvas {
            width: 100% !important;
            height: 100% !important;
        }
    </style>
</head>
<body>
    <h2>✨ 数据看板 ✨</h2>
    <div class="chart-container">
        <div class="chart-box"><canvas id="barChart"></canvas></div>
        <div class="chart-box"><canvas id="pieChart"></canvas></div>
        <div class="chart-box"><canvas id="lineChart"></canvas></div>
        <div class="chart-box"><canvas id="scatterChart"></canvas></div>
    </div>
    <script>
        fetch('/api/data')
            .then(response => response.json())
            .then(data => {
                // 1. 准备数据
                const categories = [...new Set(data.map(item => item.category))];
                const months = Array.from({ length: 12 }, (_, i) => `${i + 1}月`);

                let datasetMap = {};
                categories.forEach(category => {
                    datasetMap[category] = Array(12).fill(0);
                });

                data.forEach(item => {
                    datasetMap[item.category][item.month - 1] = item.value;
                });

                // 2. 随机色
                const colors = categories.map(() => `hsl(${Math.random()*360}, 80%, 60%)`);

                // 3. 柱状图
                const ctxBar = document.getElementById('barChart').getContext('2d');
                new Chart(ctxBar, {
                    type: 'bar',
                    data: {
                        labels: months,
                        datasets: categories.map((category, i) => ({
                            label: category,
                            data: datasetMap[category],
                            backgroundColor: colors[i],
                            borderColor: 'white',
                            borderWidth: 1
                        }))
                    },
                    options: { responsive: true }
                });

                // 4. 饼图
                const ctxPie = document.getElementById('pieChart').getContext('2d');
                new Chart(ctxPie, {
                    type: 'doughnut',
                    data: {
                        labels: categories,
                        datasets: [{
                            data: categories.map(category => datasetMap[category].reduce((a, b) => a + b, 0)),
                            backgroundColor: colors,
                            borderColor: 'white'
                        }]
                    },
                    options: { responsive: true }
                });

                // 5. 折线图(鼠标悬浮时显示数值)
                const ctxLine = document.getElementById('lineChart').getContext('2d');
                new Chart(ctxLine, {
                    type: 'line',
                    data: {
                        labels: months,
                        datasets: categories.map((category, i) => ({
                            label: category,
                            data: datasetMap[category],
                            borderColor: colors[i],
                            fill: false,
                            tension: 0.4,
                            pointBackgroundColor: 'white'
                        }))
                    },
                    options: {
                        responsive: true,
                        // 关键:鼠标悬浮显示数值
                        interaction: {
                            mode: 'index',
                            intersect: false
                        },
                        plugins: {
                            tooltip: {
                                enabled: true,
                                callbacks: {
                                    // 回调函数,自定义显示的文本
                                    label: function(context) {
                                        let label = context.dataset.label || '';
                                        let value = context.parsed.y !== undefined ? context.parsed.y : '';
                                        return `${label}: ${value}`;
                                    }
                                }
                            }
                        }
                    }
                });

                // 6. 散点图
                const ctxScatter = document.getElementById('scatterChart').getContext('2d');
                new Chart(ctxScatter, {
                    type: 'scatter',
                    data: {
                        datasets: categories.map((category, i) => ({
                            label: category,
                            data: datasetMap[category].map((value, index) => ({ x: index + 1, y: value })),
                            backgroundColor: colors[i],
                            borderColor: 'white',
                            pointRadius: 6
                        }))
                    },
                    options: { responsive: true }
                });
            })
            .catch(error => console.error('数据加载失败:', error));
    </script>
</body>
</html>

6. 运行 Flask 服务器

python server.py

图片

然后打开浏览器,访问:

http://127.0.0.1:5000

 点击阅读原文:《用 python、MySQL 和 Chart.js 打造炫酷数据看板》实战案例笔记

原创 IT小本本 IT小本本 2025年03月11日 21:21 北京

最终效果:

图片

相关文章:

  • SQLiteStudio:一款免费开源跨平台的SQLite管理工具
  • Kerckhoffs原理
  • 磁盘和文件系统
  • 【商城实战(23)】筑牢安全防线,防范常见漏洞
  • 【系统架构设计师】测试方法
  • 【Java项目】基于JSP的二手手机回收系统
  • Stable Diffusion 模型文件 .ckpt 与 .safetensors 的区别
  • html中利用 onerror 事件监听图片加载错误的情况
  • Android Retrofit 框架的接口代理与调用模块源码分析(二)
  • 【2025】Electron 基础二(进程模型三大核心)
  • 碳中和小程序:助力用户记录低碳行为,推动环保生活
  • 03_添加一个简单的字符设备并支持read操作
  • OpenManus测出死循环bug
  • 球衣号码选几号最好·棒球1号位
  • GStreamer —— 2.16、Windows下Qt加载GStreamer库后运行 - “播放教程 2:字幕管理“(附:完整源码)
  • 文摘:关于提问
  • maven的项目构建
  • iOS中的设计模式(八)- 桥接模式
  • 前端如何发布npm包
  • 【力扣刷题实战】查找总价格为目标值的两个商品
  • 终于,俄罗斯和乌克兰谈上了
  • 视频丨中国海警成功救助8名外籍遇险渔民,韩方向中方致谢
  • 杭州“放大招”支持足球发展:足球人才可评“高层次人才”
  • 牛市早报|中方调整对美加征关税措施,五部门约谈外卖平台企业
  • 人民日报任平:从汽车产销、外贸大盘看中国经济前景
  • 某博主遭勒索后自杀系自导自演,成都警方立案调查