Chart.js 散点图

在 React 项目中使用 Chart.js 创建散点图(Scatter Chart)是一种有效的数据可视化方式,适合展示二维数据点之间的关系,例如销售额与广告支出的相关性。结合 react-chartjs-2 库,散点图可以通过 React 组件化方式快速实现。本文以中文讲解 Chart.js 散点图的创建过程,涵盖基本用法、动态数据、样式定制、与 React Router 和 Tailwind CSS 的结合,以及注意事项,力求简洁清晰,避免重复之前的内容,并提供实用示例。


1. 散点图概述

散点图(Scatter Chart)通过在二维坐标系中绘制数据点展示变量之间的关系,每个点表示一个数据点的 x 和 y 坐标。Chart.js 的散点图支持:

  • 多数据集:展示多组数据点,区分不同类别。
  • 交互效果:支持悬停提示、点击事件。
  • 响应式:自动适配容器大小。
  • 高度可定制:调整点样式、颜色、轴等。

在 React 中,使用 react-chartjs-2<Scatter /> 组件渲染散点图。


2. 基本散点图实现

以下是在 React 中使用 Chart.js 创建一个简单散点图的示例,展示销售额与广告支出的关系。

示例代码

import { Scatter } from 'react-chartjs-2';
import { Chart as ChartJS, LinearScale, PointElement, Tooltip, Legend } from 'chart.js';

// 注册必要模块
ChartJS.register(LinearScale, PointElement, Tooltip, Legend);

function ScatterChart() {
  // 数据配置
  const data = {
    datasets: [
      {
        label: '产品数据',
        data: [
          { x: 100, y: 50 }, // x: 广告支出, y: 销售额
          { x: 150, y: 70 },
          { x: 200, y: 60 },
          { x: 250, y: 80 },
          { x: 300, y: 90 },
        ],
        backgroundColor: 'rgba(59, 130, 246, 0.6)', // 点填充颜色
        borderColor: 'rgba(59, 130, 246, 1)', // 点边框颜色
        pointRadius: 6, // 点半径
      },
    ],
  };

  // 选项配置
  const options = {
    responsive: true,
    plugins: {
      legend: {
        position: 'top',
        labels: { font: { size: 12 } },
      },
      tooltip: {
        backgroundColor: '#1f2937', // 提示框背景
        callbacks: {
          label: (context) => {
            const { x, y } = context.raw;
            return `${context.dataset.label}: (广告: ${x} 万元, 销售: ${y} 万元)`;
          },
        },
      },
      title: {
        display: true,
        text: '广告支出与销售额关系',
        font: { size: 16 },
      },
    },
    scales: {
      x: {
        title: { display: true, text: '广告支出 (万元)' },
        grid: { color: '#e5e7eb' }, // 网格颜色
        min: 0,
      },
      y: {
        title: { display: true, text: '销售额 (万元)' },
        beginAtZero: true,
        grid: { color: '#e5e7eb' },
      },
    },
  };

  return (
    <div className="w-full max-w-3xl mx-auto p-6 bg-white rounded-lg shadow-md">
      <Scatter data={data} options={options} />
    </div>
  );
}

export default ScatterChart;

说明

  • 注册模块
  • LinearScale:散点图使用线性刻度(X/Y 轴均为数值)。
  • PointElement:支持数据点的绘制。
  • TooltipLegend:交互和图例支持。
  • 数据(data)
  • 不需要 labels(X 轴由数据点的 x 值决定)。
  • datasets.data:数组中的每个对象包含 xy 坐标。
  • pointRadius:设置数据点大小。
  • 选项(options)
  • responsive: true:适配容器大小。
  • tooltip.callbacks.label:自定义提示框,显示坐标值。
  • scales:配置 X/Y 轴标题、网格和范围。
  • 容器:使用 Tailwind CSS 类(如 bg-whiterounded-lg)美化容器。

3. 多数据集散点图

散点图支持多个数据集,展示不同类别的数据点。

示例:多数据集散点图

function MultiScatterChart() {
  const data = {
    datasets: [
      {
        label: '产品 A',
        data: [
          { x: 100, y: 50 },
          { x: 150, y: 70 },
          { x: 200, y: 60 },
        ],
        backgroundColor: 'rgba(59, 130, 246, 0.6)',
        borderColor: 'rgba(59, 130, 246, 1)',
        pointRadius: 6,
      },
      {
        label: '产品 B',
        data: [
          { x: 120, y: 55 },
          { x: 180, y: 80 },
          { x: 220, y: 65 },
        ],
        backgroundColor: 'rgba(255, 99, 132, 0.6)',
        borderColor: 'rgba(255, 99, 132, 1)',
        pointRadius: 6,
      },
    ],
  };

  const options = {
    responsive: true,
    plugins: {
      legend: { position: 'top' },
      title: { display: true, text: '产品 A vs 产品 B 销售分析' },
    },
    scales: {
      x: { title: { display: true, text: '广告支出 (万元)' }, min: 0 },
      y: { title: { display: true, text: '销售额 (万元)' }, beginAtZero: true },
    },
  };

  return (
    <div className="w-full max-w-3xl mx-auto p-6 bg-white rounded-lg shadow-md">
      <Scatter data={data} options={options} />
    </div>
  );
}

说明

  • 多数据集:每个 dataset 表示一组数据点,颜色区分不同产品。
  • 视觉效果:通过 backgroundColorborderColor 区分数据集。
  • 应用场景:比较不同类别的数据点关系。

4. 动态数据更新

结合 React 的 useStateuseEffect Hooks,实现散点图的动态更新,适合实时数据展示。

示例:动态散点图

import { useState, useEffect } from 'react';
import { Scatter } from 'react-chartjs-2';
import { Chart as ChartJS, LinearScale, PointElement, Tooltip, Legend } from 'chart.js';

ChartJS.register(LinearScale, PointElement, Tooltip, Legend);

function DynamicScatterChart() {
  const [data, setData] = useState({
    datasets: [
      {
        label: '实时数据',
        data: [
          { x: 100, y: 50 },
          { x: 150, y: 70 },
          { x: 200, y: 60 },
        ],
        backgroundColor: 'rgba(34, 197, 94, 0.6)',
        borderColor: 'rgba(34, 197, 94, 1)',
        pointRadius: 6,
      },
    ],
  });

  useEffect(() => {
    const interval = setInterval(() => {
      setData(prev => ({
        ...prev,
        datasets: [
          {
            ...prev.datasets[0],
            data: prev.datasets[0].data.map(() => ({
              x: Math.random() * 300,
              y: Math.random() * 100,
            })),
          },
        ],
      }));
    }, 3000); // 每 3 秒更新
    return () => clearInterval(interval);
  }, []);

  const options = {
    responsive: true,
    plugins: {
      legend: { position: 'top' },
      title: { display: true, text: '实时数据散点图' },
    },
    scales: {
      x: { min: 0, max: 300, title: { display: true, text: 'X 轴' } },
      y: { min: 0, max: 100, title: { display: true, text: 'Y 轴' } },
    },
  };

  return (
    <div className="w-full max-w-3xl mx-auto p-6 bg-white rounded-lg shadow-md">
      <Scatter data={data} options={options} />
    </div>
  );
}

说明

  • 动态更新useEffect 每 3 秒生成随机坐标,更新散点图。
  • 性能优化:可用 useMemo 缓存 data
  const memoizedData = useMemo(() => data, [data]);
  • 范围限制:通过 scales.x.min/max 设置坐标轴范围。

5. 与 React Router 结合

将散点图嵌入 React Router 页面,适合数据分析仪表盘。

示例

import { Routes, Route, NavLink } from 'react-router-dom';
import ScatterChart from './ScatterChart';
import MultiScatterChart from './MultiScatterChart';

function App() {
  return (
    <div className="p-6">
      <nav className="mb-6 space-x-4">
        <NavLink
          to="/scatter"
          className={({ isActive }) =>
            isActive ? 'text-blue-500 font-bold' : 'text-gray-500'
          }
        >
          标准散点图
        </NavLink>
        <NavLink
          to="/multi-scatter"
          className={({ isActive }) =>
            isActive ? 'text-blue-500 font-bold' : 'text-gray-500'
          }
        >
          多数据集散点图
        </NavLink>
      </nav>
      <Routes>
        <Route path="/scatter" element={<ScatterChart />} />
        <Route path="/multi-scatter" element={<MultiScatterChart />} />
      </Routes>
    </div>
  );
}

说明

  • NavLink:切换不同散点图页面,动态添加激活样式。
  • Routes:映射散点图组件到路由路径。

6. 与 Tailwind CSS 结合

散点图渲染在 Canvas 上,外部容器可用 Tailwind CSS 美化。

示例

function ScatterChart() {
  const data = { /* 同上 */ };
  const options = { /* 同上 */ };

  return (
    <div className="bg-white p-6 rounded-lg shadow-md max-w-3xl mx-auto">
      <h2 className="text-xl font-semibold mb-4 text-center">广告与销售分析</h2>
      <Scatter data={data} options={options} />
    </div>
  );
}

说明

  • 容器样式:Tailwind 类(如 bg-whiterounded-lg)美化容器。
  • Canvas 样式:散点图内部样式由 dataoptions 控制。

7. 自定义散点图样式

通过 optionsdata 自定义散点图的外观。

示例:自定义样式

const options = {
  responsive: true,
  plugins: {
    legend: { position: 'bottom', labels: { font: { size: 12 } } },
    tooltip: {
      backgroundColor: '#111827',
      callbacks: {
        label: (context) => {
          const { x, y } = context.raw;
          return `${context.dataset.label}: (X: ${x}, Y: ${y})`;
        },
      },
    },
    title: { display: true, text: '自定义散点图', font: { size: 16 } },
  },
  scales: {
    x: { min: 0, max: 400, grid: { display: false }, title: { display: true, text: 'X 轴' } },
    y: { min: 0, max: 100, grid: { color: '#e5e7eb' }, title: { display: true, text: 'Y 轴' } },
  },
  elements: {
    point: {
      radius: 6, // 默认点大小
      hoverRadius: 8, // 悬停时放大
      backgroundColor: 'rgba(59, 130, 246, 0.6)',
      hoverBackgroundColor: 'rgba(59, 130, 246, 1)',
    },
  },
};

说明

  • 点样式elements.point 控制点大小、悬停效果和颜色。
  • Tooltip:自定义提示框内容和样式。
  • 坐标轴scales 设置范围、网格和标题。

8. 注意事项

  1. 模块注册
  • 确保注册 LinearScalePointElement,否则报错(如“Linear is not a registered scale”)。
  1. 数据格式
  • 每个数据点需包含 xy 属性。
  • 检查数据有效性,避免空数组或无效值。
  1. 性能优化
  • 使用 useMemo 缓存 dataoptions
    jsx const memoizedData = useMemo(() => data, [data]);
  • 动态更新时限制数据点数量,避免性能瓶颈。
  1. 容器尺寸
  • 确保容器有足够宽高,可通过 CSS 或 options 设置:
    jsx options: { maintainAspectRatio: false, height: 400 }
  1. 调试
  • 检查浏览器开发者工具,确保 Canvas 渲染正常。
  • 验证 data.datasets 格式,排除配置错误。

9. 资源

  • Chart.js 散点图文档:https://www.chartjs.org/docs/latest/charts/scatter.html
  • react-chartjs-2 示例:https://react-chartjs-2.js.org/examples/scatter-chart
  • 中文社区:搜索“Chart.js 散点图 中文教程”或参考掘金、知乎。

如果需要更详细的讲解(如复杂散点图配置、插件集成或交互优化),请告诉我!

类似文章

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注