FastAPI + Echarts 构建可交互数据仪表板

FastAPI + Echarts 构建可交互数据仪表板

项目概述

本项目是一个使用 uv + Python 3.14 + FastAPI 构建的 Web 服务示例。项目包含以下核心内容:

  • 静态资源托管 :通过 FastAPI 的 StaticFiles 中间件托管 static/ 目录下的静态文件。
  • CORS 跨域支持 :通过 CORSMiddleware 中间件配置跨域访问策略。
  • jQuery AJAX 示例 :首页通过本地引入的 jQuery 发起 AJAX 请求,调用 /api/hello 接口并展示返回结果。
  • ECharts 图表案例:提供折线图、柱状图、饼图、散点图四种常用图表的展示页面。
  • 图表数据接口 :通过 /api/chart-data/{chart_type} 接口为前端图表提供动态数据。

本教程将带领你了解项目的结构、启动方式以及各个功能模块的使用方法,所有代码均完整列出,按照教程即可独立完成开发。

项目目录结构

复制代码
fastapi-app/
├── main.py                         # FastAPI 入口,包含路由与中间件配置
├── pyproject.toml                   # 项目依赖配置
├── uv.lock                          # 依赖锁定文件
├── .venv/                           # 虚拟环境
├── tutorial.md                      # 本教程文档
├── docs/
│   └── images/                      # 运行效果截图
│       ├── home.png
│       ├── charts_index.png
│       ├── line.png
│       ├── bar.png
│       ├── pie.png
│       └── scatter.png
└── static/                          # 静态资源根目录
    ├── index.html                   # 首页(jQuery AJAX 示例)
    ├── js/
    │   ├── jquery-4.0.0.min.js      # 本地 jQuery 库
    │   └── echarts.min.js           # 本地 ECharts 6.1.0 库
    └── charts/                      # ECharts 图表案例目录
        ├── index.html               # 图表案例索引页
        ├── line.html                # 折线图案例
        ├── bar.html                 # 柱状图案例
        ├── pie.html                 # 饼图案例
        └── scatter.html             # 散点图案例

环境准备

在运行本项目之前,请确保你的开发环境满足以下条件:

  1. 安装 uv:uv 是一个高性能的 Python 包管理器和运行器。如果尚未安装,可以通过以下命令安装:

    bash 复制代码
    # Windows (PowerShell)
    powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"

    安装完成后,在终端中运行 uv --version 检查是否安装成功。

  2. Python 版本 :本项目使用 Python 3.14。uv 会自动根据项目配置管理 Python 版本,无需手动安装。

  3. 安装依赖:在项目根目录执行以下命令初始化虚拟环境并安装依赖:

    bash 复制代码
    # 创建 Python 3.14 虚拟环境
    uv venv --python 3.14
    
    # 初始化项目并安装 FastAPI 和 Uvicorn
    uv init
    uv add fastapi uvicorn

    安装完成后,pyproject.toml 内容如下:

    toml 复制代码
    [project]
    name = "fastapi-app"
    version = "0.1.0"
    description = "Add your description here"
    readme = "README.md"
    requires-python = ">=3.14"
    dependencies = [
        "fastapi>=0.140.13",
        "uvicorn>=0.51.0",
    ]

项目启动

在项目根目录下打开终端,执行以下命令启动服务:

bash 复制代码
uv run uvicorn main:app --host 127.0.0.1 --port 8000

命令说明:

  • uv run:使用 uv 运行项目依赖环境中的命令。
  • uvicorn:ASGI 服务器,用于运行 FastAPI 应用。
  • main:app:表示从 main.py 文件中加载名为 app 的 FastAPI 实例。
  • --host 127.0.0.1:服务监听本机地址。
  • --port 8000:服务监听 8000 端口。

启动成功后,打开浏览器访问 http://127.0.0.1:8000,即可看到项目首页。

后端入口 main.py

main.py 是整个项目的后端入口,负责创建 FastAPI 应用、挂载静态资源、配置 CORS 跨域、提供 API 接口。完整代码如下:

python 复制代码
# 从 fastapi 包导入 FastAPI 类,用于创建 Web 应用实例
from fastapi import FastAPI
# 从 fastapi.staticfiles 导入 StaticFiles,用于挂载静态文件目录
from fastapi.staticfiles import StaticFiles
# 从 fastapi.middleware.cors 导入 CORSMiddleware,用于处理跨域请求
from fastapi.middleware.cors import CORSMiddleware
# 从 fastapi.responses 导入 FileResponse,用于返回本地文件作为响应
from fastapi.responses import FileResponse
# 从 fastapi 导入 HTTPException,用于返回 HTTP 错误响应
from fastapi import HTTPException

# 创建 FastAPI 应用实例,app 是整个 Web 服务的入口对象
app = FastAPI()

# 挂载静态文件服务:
# 第一个参数 "/static" 是 URL 路径前缀,
# StaticFiles(directory="static") 指定本地 static 目录为静态资源根目录,
# name="static" 是给该挂载点起的名称,便于反向生成 URL
app.mount("/static", StaticFiles(directory="static"), name="static")

# 为 FastAPI 应用添加 CORS(跨域资源共享)中间件
app.add_middleware(
    # 使用 CORSMiddleware 中间件类
    CORSMiddleware,
    # allow_origins 允许的来源列表,["*"] 表示允许所有来源访问
    allow_origins=["*"],
    # allow_credentials 是否允许携带身份凭证(如 Cookie),
    # 由于与 allow_origins=["*"] 配合时需要反射 Origin,这里设为 False 以直接返回 *
    allow_credentials=False,
    # allow_methods 允许的 HTTP 方法列表,["*"] 表示允许 GET/POST/PUT/DELETE 等所有方法
    allow_methods=["*"],
    # allow_headers 允许的请求头列表,["*"] 表示允许所有自定义请求头
    allow_headers=["*"],
)

# 定义根路径 "/" 的 GET 路由
@app.get("/")
# 路由处理函数:当用户访问首页时执行
def read_root():
    # 返回 static/index.html 文件内容,作为首页展示
    return FileResponse("static/index.html")

# 定义 "/api/hello" 路径的 GET 路由,用于前端 AJAX 调用测试
@app.get("/api/hello")
# 路由处理函数:返回一段 JSON 数据
def read_hello():
    # 返回包含 message 字段的字典,FastAPI 会自动将其序列化为 JSON
    return {"message": "Hello from FastAPI!"}


# 定义 "/api/chart-data/{chart_type}" 路径的 GET 路由,用于返回 ECharts 图表数据
@app.get("/api/chart-data/{chart_type}")
# 路由处理函数:根据 chart_type 返回对应类型的图表数据
def get_chart_data(chart_type: str):
    # 允许的图表类型列表
    allowed_types = {"line", "bar", "pie", "scatter"}
    # 如果请求的类型不在允许列表中,返回 HTTP 400 错误
    if chart_type not in allowed_types:
        raise HTTPException(status_code=400, detail=f"Invalid chart_type: {chart_type}. Allowed values: line, bar, pie, scatter")

    # line 类型:返回折线图数据
    if chart_type == "line":
        return {
            "categories": ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
            "values": [120, 200, 150, 80, 70, 110, 130],
        }

    # bar 类型:返回柱状图数据
    if chart_type == "bar":
        return {
            "categories": ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
            "values": [120, 200, 150, 80, 70, 110, 130],
        }

    # pie 类型:返回饼图数据
    if chart_type == "pie":
        return {
            "data": [
                {"value": 1048, "name": "Search Engine"},
                {"value": 735, "name": "Direct"},
                {"value": 580, "name": "Email"},
                {"value": 484, "name": "Union Ads"},
                {"value": 300, "name": "Video Ads"},
            ]
        }

    # scatter 类型:返回散点图数据
    if chart_type == "scatter":
        return {
            "data": [
                [10.0, 8.04],
                [8.0, 6.95],
                [13.0, 7.58],
                [9.0, 8.81],
                [11.0, 8.33],
                [14.0, 9.96],
                [6.0, 7.24],
                [4.0, 4.26],
                [12.0, 10.84],
                [7.0, 4.82],
                [5.0, 5.68],
            ]
        }

静态资源托管

本项目使用 FastAPI 提供的 StaticFilesstatic/ 目录挂载为静态资源目录:

python 复制代码
app.mount("/static", StaticFiles(directory="static"), name="static")
  • static/ 目录下的所有文件(如 HTML、CSS、JavaScript、图片等)都可以通过 /static/文件名 的路径访问。
  • 首页路由(/)会直接返回 static/index.html 文件的内容,因此访问 http://127.0.0.1:8000 时,看到的就是首页页面。

CORS 跨域配置

CORS(Cross-Origin Resource Sharing,跨域资源共享)是一种浏览器安全机制,允许或限制不同源(域名、端口、协议)之间的资源请求。本项目配置了 CORSMiddleware 中间件来处理跨域请求:

python 复制代码
app.add_middleware(
    CORSMiddleware,
    allow_origins=["*"],       # 允许所有来源访问
    allow_credentials=False,   # 不携带 Cookie 等凭据(与 "*" 配合时必须为 False)
    allow_methods=["*"],       # 允许所有 HTTP 方法
    allow_headers=["*"],        # 允许所有自定义请求头
)

各参数含义:

  • allow_origins:允许访问的源列表。设置为 ["*"] 表示允许所有来源。
  • allow_credentials:是否允许携带 Cookie 等凭据信息。注意:当 allow_origins["*"] 时,Starlette 会反射实际 Origin 而非返回 *,因此需设为 False 才能直接返回 Access-Control-Allow-Origin: *
  • allow_methods:允许的 HTTP 方法列表,例如 GETPOST 等。
  • allow_headers:允许的请求头列表。

通过该配置,前端页面可以正常向后端接口发起请求,而不会被浏览器拦截。

图表数据接口

前端图表页面通过调用后端接口获取数据,接口路径为:

复制代码
GET /api/chart-data/{chart_type}

其中 {chart_type} 为图表类型参数,支持以下取值:

  • line:折线图
  • bar:柱状图
  • pie:饼图
  • scatter:散点图

如果传入不支持的类型,接口将返回 HTTP 400 错误,提示允许的参数值。

各类型返回的 JSON 数据结构

折线图(line)

返回 categories 作为 X 轴类目数据,values 作为对应的系列数值:

json 复制代码
{
  "categories": ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
  "values": [120, 200, 150, 80, 70, 110, 130]
}
柱状图(bar)

与折线图数据结构相同,使用 categories 作为类目,values 作为柱子高度:

json 复制代码
{
  "categories": ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
  "values": [120, 200, 150, 80, 70, 110, 130]
}
饼图(pie)

返回 data 数组,每个元素包含 value(数值)和 name(名称):

json 复制代码
{
  "data": [
    {"value": 1048, "name": "Search Engine"},
    {"value": 735, "name": "Direct"},
    {"value": 580, "name": "Email"},
    {"value": 484, "name": "Union Ads"},
    {"value": 300, "name": "Video Ads"}
  ]
}
散点图(scatter)

返回 data 数组,每个元素为包含 X 轴和 Y 轴取值的二维数组:

json 复制代码
{
  "data": [
    [10.0, 8.04],
    [8.0, 6.95],
    [13.0, 7.58],
    [9.0, 8.81],
    [11.0, 8.33],
    [14.0, 9.96],
    [6.0, 7.24],
    [4.0, 4.26],
    [12.0, 10.84],
    [7.0, 4.82],
    [5.0, 5.68]
  ]
}

首页 static/index.html

首页展示了 jQuery AJAX 的基本用法:页面引入本地 jQuery,点击按钮后通过 AJAX 调用 /api/hello 接口,并将返回结果展示在页面上。同时页面底部提供了进入 ECharts 图表案例的入口链接。完整代码如下:

html 复制代码
<!-- 声明文档类型为 HTML5 -->
<!DOCTYPE html>
<!-- 根元素,lang="en" 表示页面主要语言为英文 -->
<html lang="en">
<!-- head 区域:包含页面的元数据、标题和样式 -->
<head>
    <!-- 设置字符编码为 UTF-8,防止中文等字符乱码 -->
    <meta charset="UTF-8">
    <!-- 设置视口,使页面在移动设备上自适应宽度 -->
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <!-- 设置浏览器标签页上显示的页面标题 -->
    <title>FastAPI Static Demo</title>
    <!-- style 标签:定义页面内部 CSS 样式 -->
    <style>
        /* body 选择器:设置整个页面的基础样式 */
        body {
            /* 设置页面字体为 Arial,若不可用则使用无衬线字体 */
            font-family: Arial, sans-serif;
            /* 设置内容区域最大宽度为 600 像素 */
            max-width: 600px;
            /* 上下外边距 50px,左右自动居中 */
            margin: 50px auto;
            /* 内边距 20 像素 */
            padding: 20px;
        }
        /* button 选择器:设置按钮样式 */
        button {
            /* 上下内边距 10px,左右内边距 20px */
            padding: 10px 20px;
            /* 字体大小 16 像素 */
            font-size: 16px;
            /* 鼠标悬停时显示手型指针 */
            cursor: pointer;
        }
        /* #result 选择器:设置结果显示区域的样式 */
        #result {
            /* 上方外边距 20 像素,与按钮分隔 */
            margin-top: 20px;
            /* 内边距 15 像素 */
            padding: 15px;
            /* 1 像素宽度的浅灰色实线边框 */
            border: 1px solid #ddd;
            /* 边框圆角 4 像素 */
            border-radius: 4px;
            /* 背景色为浅灰 */
            background-color: #f9f9f9;
            /* 最小高度 20 像素,保证空时也有占位 */
            min-height: 20px;
        }
    </style>
</head>
<!-- body 区域:页面可见内容 -->
<body>
    <!-- 页面主标题 -->
    <h1>FastAPI Static Demo</h1>
    <!-- 按钮,用户点击后触发 AJAX 请求,id="fetchBtn" 用于 JavaScript 选择 -->
    <button id="fetchBtn">Fetch Message</button>
    <!-- 用于展示 AJAX 请求结果的区域,id="result" 用于 JavaScript 填充内容 -->
    <div id="result"></div>

    <!-- 新增:ECharts 图表案例入口链接 -->
    <div style="margin-top: 30px; text-align: center;">
        <a href="/static/charts/index.html" style="display: inline-block; padding: 10px 20px; font-size: 16px; color: #fff; background-color: #1e88e5; text-decoration: none; border-radius: 6px; transition: background-color 0.3s ease;">
            查看 ECharts 图表案例
        </a>
    </div>

    <!-- 引入本地 static/js 目录下的 jQuery 文件,用于发起 AJAX 请求 -->
    <script src="/static/js/jquery-4.0.0.min.js"></script>
    <!-- script 标签:页面内部 JavaScript 逻辑 -->
    <script>
        // 等待整个 HTML 文档加载完成后再执行
        $(document).ready(function() {
            // 定义 fetchMessage 函数,用于向后端发起 AJAX 请求
            function fetchMessage() {
                // 使用 jQuery 的 ajax 方法发起异步 HTTP 请求
                $.ajax({
                    // 请求目标地址,即 FastAPI 提供的 /api/hello 接口
                    url: '/api/hello',
                    // 使用 HTTP GET 方法
                    method: 'GET',
                    // 请求成功时的回调函数,data 为后端返回的 JSON 数据
                    success: function(data) {
                        // 将返回数据中的 message 字段设置为 result div 的文本内容
                        $('#result').text(data.message);
                    },
                    // 请求失败时的回调函数
                    error: function(xhr, status, error) {
                        // 在 result 区域显示错误信息
                        $('#result').text('Error: ' + error);
                    }
                });
            }

            // 为 id="fetchBtn" 的按钮绑定点击事件,点击时调用 fetchMessage 函数
            $('#fetchBtn').on('click', fetchMessage);
        });
    </script>
</body>
</html>

jQuery AJAX 示例说明

示例流程如下:

  1. 页面加载完成后,jQuery 发起一个 GET 请求到 /api/hello

  2. 后端返回一段 JSON 数据,例如:

    json 复制代码
    {
      "message": "Hello from FastAPI!"
    }
  3. 前端接收到响应后,将返回的内容展示在页面指定区域。

这种方式展示了前后端交互的基本流程,也是本项目中 AJAX 调用的典型用法。

常用图表案例

本项目集成了 ECharts 图表库,并在 static/charts/ 目录下存放了四种常用图表的案例页面。每个案例页面均通过 <script> 标签引入本地 static/js/echarts.min.jsstatic/js/jquery-4.0.0.min.js,然后使用 jQuery 的 $.ajax() 方法从 /api/chart-data/{chart_type} 接口获取动态数据,最后调用 ECharts 渲染图表。

项目启动后,可通过浏览器直接访问以下页面查看效果。

图表案例索引页 static/charts/index.html

图表索引页汇总了所有图表案例入口,使用 CSS Grid 布局展示卡片式导航。完整代码如下:

html 复制代码
<!-- 声明文档类型为 HTML5 -->
<!DOCTYPE html>
<!-- 根元素,页面主要语言为中文 -->
<html lang="zh-CN">
<!-- head 区域:包含页面的元数据、标题和样式 -->
<head>
    <!-- 设置字符编码为 UTF-8,防止中文等字符乱码 -->
    <meta charset="UTF-8">
    <!-- 设置视口,使页面在移动设备上自适应宽度 -->
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <!-- 设置浏览器标签页上显示的页面标题 -->
    <title>ECharts 图表案例索引</title>
    <!-- style 标签:定义页面内部 CSS 样式 -->
    <style>
        /* body 选择器:设置整个页面的基础样式 */
        body {
            /* 设置页面字体,优先使用微软雅黑,保证中文显示美观 */
            font-family: Arial, "Microsoft YaHei", sans-serif;
            /* 页面背景色为浅灰 */
            background-color: #f5f5f5;
            /* 外边距和内边距清零 */
            margin: 0;
            padding: 0;
        }
        /* 页面容器,限制最大宽度并居中显示 */
        .container {
            /* 最大宽度 800 像素 */
            max-width: 800px;
            /* 上下外边距 60px,左右自动居中 */
            margin: 60px auto;
            /* 内边距 30 像素 */
            padding: 30px;
            /* 背景色为白色 */
            background-color: #fff;
            /* 边框圆角 12 像素 */
            border-radius: 12px;
            /* 添加轻微阴影,增强层次感 */
            box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
        }
        /* 页面主标题样式 */
        h1 {
            /* 文字居中 */
            text-align: center;
            /* 字体颜色为深灰 */
            color: #333;
            /* 底部外边距 10 像素 */
            margin-bottom: 10px;
        }
        /* 副标题/说明文字样式 */
        .subtitle {
            /* 文字居中 */
            text-align: center;
            /* 字体颜色为灰色 */
            color: #666;
            /* 底部外边距 30 像素 */
            margin-bottom: 30px;
        }
        /* 图表入口网格布局 */
        .chart-grid {
            /* 使用 CSS Grid 布局 */
            display: grid;
            /* 每列最小 160px,自动填充剩余空间 */
            grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
            /* 网格间距 20 像素 */
            gap: 20px;
            /* 底部外边距 30 像素 */
            margin-bottom: 30px;
        }
        /* 单个图表入口卡片样式 */
        .chart-card {
            /* 块级弹性布局 */
            display: flex;
            /* 垂直方向排列 */
            flex-direction: column;
            /* 内容水平垂直居中 */
            align-items: center;
            justify-content: center;
            /* 内边距 20 像素 */
            padding: 20px;
            /* 字体大小 18 像素 */
            font-size: 18px;
            /* 字体加粗 */
            font-weight: bold;
            /* 文字颜色为深蓝色 */
            color: #1e88e5;
            /* 去除下划线 */
            text-decoration: none;
            /* 边框为 1 像素浅蓝实线 */
            border: 1px solid #e3f2fd;
            /* 边框圆角 8 像素 */
            border-radius: 8px;
            /* 背景色为浅蓝 */
            background-color: #fafafa;
            /* 鼠标悬停时显示手型指针 */
            cursor: pointer;
            /* 添加过渡动画,使悬停效果更平滑 */
            transition: all 0.3s ease;
        }
        /* 图表入口卡片悬停效果 */
        .chart-card:hover {
            /* 悬停时背景色变为浅蓝 */
            background-color: #e3f2fd;
            /* 阴影加深 */
            box-shadow: 0 4px 12px rgba(30, 136, 229, 0.2);
            /* 整体向上移动 2 像素 */
            transform: translateY(-2px);
        }
        /* 图表图标样式 */
        .chart-icon {
            /* 图标字体大小 32 像素 */
            font-size: 32px;
            /* 底部外边距 10 像素 */
            margin-bottom: 10px;
        }
        /* 返回首页链接容器 */
        .home-link {
            /* 文字居中 */
            text-align: center;
        }
        /* 返回首页链接样式 */
        .home-link a {
            /* 链接颜色为蓝色 */
            color: #1e88e5;
            /* 去除下划线 */
            text-decoration: none;
        }
        /* 返回首页链接悬停效果 */
        .home-link a:hover {
            /* 悬停时显示下划线 */
            text-decoration: underline;
        }
    </style>
</head>
<!-- body 区域:页面可见内容 -->
<body>
    <!-- 页面主容器 -->
    <div class="container">
        <!-- 页面主标题 -->
        <h1>ECharts 图表案例索引</h1>
        <!-- 页面副标题说明 -->
        <p class="subtitle">点击下方任意卡片查看对应的 ECharts 图表案例</p>

        <!-- 图表案例入口网格 -->
        <div class="chart-grid">
            <!-- 折线图案例入口 -->
            <a href="line.html" class="chart-card">
                <span class="chart-icon">&#128200;</span>
                <span>折线图</span>
            </a>
            <!-- 柱状图案例入口 -->
            <a href="bar.html" class="chart-card">
                <span class="chart-icon">&#128202;</span>
                <span>柱状图</span>
            </a>
            <!-- 饼图案例入口 -->
            <a href="pie.html" class="chart-card">
                <span class="chart-icon">&#9681;</span>
                <span>饼图</span>
            </a>
            <!-- 散点图案例入口 -->
            <a href="scatter.html" class="chart-card">
                <span class="chart-icon">&#10022;</span>
                <span>散点图</span>
            </a>
        </div>

        <!-- 返回首页链接 -->
        <div class="home-link">
            <a href="/">&larr; 返回首页</a>
        </div>
    </div>
</body>
</html>

图表索引页运行效果如下:

折线图 static/charts/line.html

  • 访问 URLhttp://127.0.0.1:8000/static/charts/line.html
  • 数据接口/api/chart-data/line
  • 特点简述:折线图通过连续的线段连接各个数据点,适合展示数据随时间变化的趋势。本案例展示了一周内销售额的变化趋势,并带有平滑曲线和面积填充效果。

完整代码如下:

html 复制代码
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>ECharts 折线图入门</title>
    <!-- 引入本地 ECharts -->
    <script src="/static/js/echarts.min.js"></script>
    <!-- 引入本地 jQuery,用于 AJAX 请求 -->
    <script src="/static/js/jquery-4.0.0.min.js"></script>
    <style>
        body {
            font-family: Arial, "Microsoft YaHei", sans-serif;
            margin: 0;
            padding: 20px;
            background-color: #f5f5f5;
        }
        h1 {
            text-align: center;
            color: #333;
        }
        /* 返回链接样式 */
        .back-link {
            display: inline-block;
            margin-bottom: 15px;
            color: #1e88e5;
            text-decoration: none;
        }
        .back-link:hover {
            text-decoration: underline;
        }
        /* 图表容器,需要明确宽高 */
        #main {
            width: 100%;
            height: 500px;
            background-color: #fff;
            border-radius: 8px;
            box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
        }
    </style>
</head>
<body>
    <!-- 返回图表索引页 -->
    <a href="/static/charts/index.html" class="back-link">&larr; 返回图表案例索引</a>
    <h1>ECharts 折线图入门</h1>
    <!-- 图表渲染容器 -->
    <div id="main"></div>

    <script>
        $(document).ready(function () {
            // 初始化 ECharts 实例
            var myChart = echarts.init(document.getElementById('main'));

            // 显示加载动画,提升用户体验
            myChart.showLoading();

            // 使用 jQuery AJAX 获取折线图数据
            $.ajax({
                url: '/api/chart-data/line',
                type: 'GET',
                dataType: 'json',
                success: function (response) {
                    // 隐藏加载动画
                    myChart.hideLoading();

                    // 构造 ECharts 配置项
                    var option = {
                        title: {
                            text: '月度销售额趋势',
                            left: 'center'
                        },
                        tooltip: {
                            trigger: 'axis'
                        },
                        legend: {
                            data: ['销售额'],
                            bottom: 0
                        },
                        grid: {
                            left: '3%',
                            right: '4%',
                            bottom: '10%',
                            containLabel: true
                        },
                        xAxis: {
                            type: 'category',
                            boundaryGap: false,
                            // 使用接口返回的 categories 作为 x 轴数据
                            data: response.categories
                        },
                        yAxis: {
                            type: 'value',
                            name: '销售额(万元)'
                        },
                        series: [{
                            name: '销售额',
                            type: 'line',
                            // 使用接口返回的 values 作为 series 数据
                            data: response.values,
                            smooth: true,
                            areaStyle: {
                                opacity: 0.2
                            }
                        }]
                    };

                    // 渲染图表
                    myChart.setOption(option);
                },
                error: function (xhr, status, error) {
                    myChart.hideLoading();
                    console.error('获取折线图数据失败:', status, error);
                    document.getElementById('main').innerHTML =
                        '<p style="text-align:center; padding-top: 200px; color: #c00;">数据加载失败,请检查接口是否正常。</p>';
                }
            });

            // 窗口大小变化时重绘图表
            $(window).resize(function () {
                myChart.resize();
            });
        });
    </script>
</body>
</html>

折线图页面运行效果如下:

柱状图 static/charts/bar.html

  • 访问 URLhttp://127.0.0.1:8000/static/charts/bar.html
  • 数据接口/api/chart-data/bar
  • 特点简述:柱状图使用矩形柱子的高度表示数值大小,适合对比不同类别之间的数据差异。本案例展示了周一至周日各天的销售额对比。

完整代码如下:

html 复制代码
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>ECharts 柱状图入门</title>
    <!-- 引入本地 ECharts -->
    <script src="/static/js/echarts.min.js"></script>
    <!-- 引入本地 jQuery,用于 AJAX 请求 -->
    <script src="/static/js/jquery-4.0.0.min.js"></script>
    <style>
        body {
            font-family: Arial, "Microsoft YaHei", sans-serif;
            margin: 0;
            padding: 20px;
            background-color: #f5f5f5;
        }
        h1 {
            text-align: center;
            color: #333;
        }
        /* 返回链接样式 */
        .back-link {
            display: inline-block;
            margin-bottom: 15px;
            color: #1e88e5;
            text-decoration: none;
        }
        .back-link:hover {
            text-decoration: underline;
        }
        /* 图表容器,需要明确宽高 */
        #main {
            width: 100%;
            height: 500px;
            background-color: #fff;
            border-radius: 8px;
            box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
        }
    </style>
</head>
<body>
    <!-- 返回图表索引页 -->
    <a href="/static/charts/index.html" class="back-link">&larr; 返回图表案例索引</a>
    <h1>ECharts 柱状图入门</h1>
    <!-- 图表渲染容器 -->
    <div id="main"></div>

    <script>
        $(document).ready(function () {
            // 初始化 ECharts 实例
            var myChart = echarts.init(document.getElementById('main'));

            // 显示加载动画
            myChart.showLoading();

            // 使用 jQuery AJAX 获取柱状图数据
            $.ajax({
                url: '/api/chart-data/bar',
                type: 'GET',
                dataType: 'json',
                success: function (response) {
                    // 隐藏加载动画
                    myChart.hideLoading();

                    // 构造 ECharts 配置项
                    var option = {
                        title: {
                            text: '各品类销量对比',
                            left: 'center'
                        },
                        tooltip: {
                            trigger: 'axis',
                            axisPointer: {
                                type: 'shadow'
                            }
                        },
                        legend: {
                            data: ['销量'],
                            bottom: 0
                        },
                        grid: {
                            left: '3%',
                            right: '4%',
                            bottom: '10%',
                            containLabel: true
                        },
                        xAxis: {
                            type: 'category',
                            // 使用接口返回的 categories 作为 x 轴数据
                            data: response.categories
                        },
                        yAxis: {
                            type: 'value',
                            name: '销量(件)'
                        },
                        series: [{
                            name: '销量',
                            type: 'bar',
                            // 使用接口返回的 values 作为 series 数据
                            data: response.values,
                            itemStyle: {
                                color: '#5470c6'
                            }
                        }]
                    };

                    // 渲染图表
                    myChart.setOption(option);
                },
                error: function (xhr, status, error) {
                    myChart.hideLoading();
                    console.error('获取柱状图数据失败:', status, error);
                    document.getElementById('main').innerHTML =
                        '<p style="text-align:center; padding-top: 200px; color: #c00;">数据加载失败,请检查接口是否正常。</p>';
                }
            });

            // 窗口大小变化时重绘图表
            $(window).resize(function () {
                myChart.resize();
            });
        });
    </script>
</body>
</html>

柱状图页面运行效果如下:

饼图 static/charts/pie.html

  • 访问 URLhttp://127.0.0.1:8000/static/charts/pie.html
  • 数据接口/api/chart-data/pie
  • 特点简述:饼图将整体划分为多个扇形区域,各区域面积表示该类别占总体的比例,适合展示构成关系。本案例展示了不同营销渠道带来的流量占比。

完整代码如下:

html 复制代码
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>ECharts 饼图入门</title>
    <!-- 引入本地 ECharts -->
    <script src="/static/js/echarts.min.js"></script>
    <!-- 引入本地 jQuery,用于 AJAX 请求 -->
    <script src="/static/js/jquery-4.0.0.min.js"></script>
    <style>
        body {
            font-family: Arial, "Microsoft YaHei", sans-serif;
            margin: 0;
            padding: 20px;
            background-color: #f5f5f5;
        }
        h1 {
            text-align: center;
            color: #333;
        }
        /* 返回链接样式 */
        .back-link {
            display: inline-block;
            margin-bottom: 15px;
            color: #1e88e5;
            text-decoration: none;
        }
        .back-link:hover {
            text-decoration: underline;
        }
        /* 图表容器,需要明确宽高 */
        #main {
            width: 100%;
            height: 500px;
            background-color: #fff;
            border-radius: 8px;
            box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
        }
    </style>
</head>
<body>
    <!-- 返回图表索引页 -->
    <a href="/static/charts/index.html" class="back-link">&larr; 返回图表案例索引</a>
    <h1>ECharts 饼图入门</h1>
    <!-- 图表渲染容器 -->
    <div id="main"></div>

    <script>
        $(document).ready(function () {
            // 初始化 ECharts 实例
            var myChart = echarts.init(document.getElementById('main'));

            // 显示加载动画
            myChart.showLoading();

            // 使用 jQuery AJAX 获取饼图数据
            $.ajax({
                url: '/api/chart-data/pie',
                type: 'GET',
                dataType: 'json',
                success: function (response) {
                    // 隐藏加载动画
                    myChart.hideLoading();

                    // 构造 ECharts 配置项
                    var option = {
                        title: {
                            text: '访问来源分布',
                            left: 'center'
                        },
                        tooltip: {
                            trigger: 'item',
                            formatter: '{a} <br/>{b}: {c} ({d}%)'
                        },
                        legend: {
                            orient: 'vertical',
                            left: 'left'
                        },
                        series: [{
                            name: '访问来源',
                            type: 'pie',
                            radius: '55%',
                            center: ['50%', '55%'],
                            // 使用接口返回的 data 数组作为 series 数据
                            data: response.data,
                            emphasis: {
                                itemStyle: {
                                    shadowBlur: 10,
                                    shadowOffsetX: 0,
                                    shadowColor: 'rgba(0, 0, 0, 0.5)'
                                }
                            }
                        }]
                    };

                    // 渲染图表
                    myChart.setOption(option);
                },
                error: function (xhr, status, error) {
                    myChart.hideLoading();
                    console.error('获取饼图数据失败:', status, error);
                    document.getElementById('main').innerHTML =
                        '<p style="text-align:center; padding-top: 200px; color: #c00;">数据加载失败,请检查接口是否正常。</p>';
                }
            });

            // 窗口大小变化时重绘图表
            $(window).resize(function () {
                myChart.resize();
            });
        });
    </script>
</body>
</html>

饼图页面运行效果如下:

散点图 static/charts/scatter.html

  • 访问 URLhttp://127.0.0.1:8000/static/charts/scatter.html
  • 数据接口/api/chart-data/scatter
  • 特点简述:散点图使用二维坐标系中的点表示两个变量的取值,适合观察变量之间的分布和相关性。本案例展示了一组样本数据的分布情况。

完整代码如下:

html 复制代码
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>ECharts 散点图入门</title>
    <!-- 引入本地 ECharts -->
    <script src="/static/js/echarts.min.js"></script>
    <!-- 引入本地 jQuery,用于 AJAX 请求 -->
    <script src="/static/js/jquery-4.0.0.min.js"></script>
    <style>
        body {
            font-family: Arial, "Microsoft YaHei", sans-serif;
            margin: 0;
            padding: 20px;
            background-color: #f5f5f5;
        }
        h1 {
            text-align: center;
            color: #333;
        }
        /* 返回链接样式 */
        .back-link {
            display: inline-block;
            margin-bottom: 15px;
            color: #1e88e5;
            text-decoration: none;
        }
        .back-link:hover {
            text-decoration: underline;
        }
        /* 图表容器,需要明确宽高 */
        #main {
            width: 100%;
            height: 500px;
            background-color: #fff;
            border-radius: 8px;
            box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
        }
    </style>
</head>
<body>
    <!-- 返回图表索引页 -->
    <a href="/static/charts/index.html" class="back-link">&larr; 返回图表案例索引</a>
    <h1>ECharts 散点图入门</h1>
    <!-- 图表渲染容器 -->
    <div id="main"></div>

    <script>
        $(document).ready(function () {
            // 初始化 ECharts 实例
            var myChart = echarts.init(document.getElementById('main'));

            // 显示加载动画
            myChart.showLoading();

            // 使用 jQuery AJAX 获取散点图数据
            $.ajax({
                url: '/api/chart-data/scatter',
                type: 'GET',
                dataType: 'json',
                success: function (response) {
                    // 隐藏加载动画
                    myChart.hideLoading();

                    // 构造 ECharts 配置项
                    var option = {
                        title: {
                            text: '身高体重分布',
                            left: 'center'
                        },
                        tooltip: {
                            trigger: 'item',
                            formatter: function (params) {
                                return '身高:' + params.data[0] + 'cm<br/>体重:' + params.data[1] + 'kg';
                            }
                        },
                        legend: {
                            data: ['人群分布'],
                            bottom: 0
                        },
                        grid: {
                            left: '7%',
                            right: '7%',
                            bottom: '10%',
                            top: '15%'
                        },
                        xAxis: {
                            type: 'value',
                            name: '身高(cm)',
                            scale: true
                        },
                        yAxis: {
                            type: 'value',
                            name: '体重(kg)',
                            scale: true
                        },
                        series: [{
                            name: '人群分布',
                            type: 'scatter',
                            symbolSize: 16,
                            // 使用接口返回的 data 二维数组作为 series 数据
                            data: response.data,
                            itemStyle: {
                                color: '#91cc75'
                            }
                        }]
                    };

                    // 渲染图表
                    myChart.setOption(option);
                },
                error: function (xhr, status, error) {
                    myChart.hideLoading();
                    console.error('获取散点图数据失败:', status, error);
                    document.getElementById('main').innerHTML =
                        '<p style="text-align:center; padding-top: 200px; color: #c00;">数据加载失败,请检查接口是否正常。</p>';
                }
            });

            // 窗口大小变化时重绘图表
            $(window).resize(function () {
                myChart.resize();
            });
        });
    </script>
</body>
</html>

散点图页面运行效果如下:

运行效果

启动服务后,打开浏览器访问以下地址,即可看到对应的页面效果:

首页 http://127.0.0.1:8000/ 的效果:

图表索引页 http://127.0.0.1:8000/static/charts/index.html 的效果:

折线图页面 http://127.0.0.1:8000/static/charts/line.html 的效果:

柱状图页面 http://127.0.0.1:8000/static/charts/bar.html 的效果:

饼图页面 http://127.0.0.1:8000/static/charts/pie.html 的效果:

散点图页面 http://127.0.0.1:8000/static/charts/scatter.html 的效果:

相关推荐
未知违规用户3 小时前
大模型项目: 学习FastAPI 服务器开发
服务器·人工智能·python·学习·fastapi
普通网友16 小时前
Python FastAPI 异步数据库管理
数据库·fastapi
观察员20 小时前
深入理解 Pydantic 的 BaseModel
fastapi
郝同学今天有进步吗1 天前
构建 LangGraph Code Review Agent(七):实现规则匹配、Finding Guardrails 与 Markdown 报告
python·ai·fastapi·code review
智购科技自动售货机工厂1 天前
即时零售的风吹到自动售货机行业,会带来什么变化?~YH
大数据·人工智能·django·fastapi·零售·tornado
初圣魔门首席弟子1 天前
FastAPI 框架完全指南
fastapi
Jacky-0082 天前
FastAPI+PostgreSQL+SQLAlchemy2.0+asyncpg异步+alembic数据迁移==项目开发
fastapi
郭老二2 天前
【Python】Web框架 FastAPI 详解
python·fastapi
中科致研zkzhiyan2 天前
锚定评委评审视角,构建科研重点项目申报答辩PPT闭环逻辑框架
信息可视化·powerpoint·ppt