您现在的位置是:网站首页 > 异常检测可视化文章详情

异常检测可视化

异常检测可视化的核心需求

异常检测可视化需要直观展示数据中的离群点、异常模式或突发变化。传统表格形式难以快速识别异常,而可视化能将数据分布、趋势和异常值转化为图形元素,利用颜色、形状、大小等视觉通道突出异常。ECharts 提供了丰富的图表类型和交互功能,特别适合构建动态、多维度的异常检测可视化方案。

ECharts 基础图表选择

折线图与面积图

折线图能清晰展示时间序列数据的波动情况,通过标记点或分段着色突出异常值:

option = {
  xAxis: { type: 'category', data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'] },
  yAxis: { type: 'value' },
  series: [{
    data: [820, 932, 901, 934, 1290, 1330, 1320],
    type: 'line',
    markPoint: {
      data: [
        { type: 'max', name: 'Max' },
        { type: 'min', name: 'Min' }
      ]
    },
    markArea: {
      data: [[
        { xAxis: 'Tue' },
        { xAxis: 'Thu' }
      ]]
    }
  }]
};

散点图与气泡图

散点图通过坐标位置和点大小展示多维数据异常:

option = {
  xAxis: { scale: true },
  yAxis: { scale: true },
  series: [{
    type: 'scatter',
    symbolSize: function (data) {
      return Math.sqrt(data[2]) * 5;
    },
    data: [
      [10.0, 8.04, 10], [8.0, 6.95, 20], 
      [13.0, 7.58, 50], [9.0, 8.81, 10],
      [11.0, 8.33, 30], [14.0, 9.96, 10],
      [6.0, 7.24, 25], [4.0, 4.26, 100],  // 异常点
      [12.0, 10.84, 9], [7.0, 4.82, 15],
      [5.0, 5.68, 12]
    ],
    itemStyle: {
      color: function(params) {
        return params.data[2] > 50 ? '#ff0000' : '#5470c6';
      }
    }
  }]
};

高级异常检测可视化技术

箱线图与离群点

箱线图自动计算并显示四分位数和离群值:

option = {
  dataset: [{
    source: [
      [850, 740, 900, 1070, 930, 850, 950],
      [960, 940, 960, 940, 880, 800, 850],
      [880, 800, 850, 880, 840, 790, 810],
      [890, 840, 780, 810, 760, 810, 1000] // 包含异常值
    ]
  }, {
    transform: {
      type: 'boxplot',
      config: { itemNameFormatter: 'expr {value}' }
    }
  }],
  xAxis: { type: 'category' },
  yAxis: { type: 'value' },
  series: [{
    name: 'boxplot',
    type: 'boxplot',
    datasetIndex: 1
  }]
};

热力图与矩阵图

热力图通过颜色梯度展示数据密度和异常区域:

option = {
  tooltip: { position: 'top' },
  grid: { height: '50%', top: '10%' },
  xAxis: { type: 'category', data: ['12a', '1a', '2a', '3a', '4a', '5a'] },
  yAxis: { type: 'category', data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri'] },
  visualMap: {
    min: 0,
    max: 10,
    calculable: true,
    orient: 'horizontal',
    left: 'center',
    bottom: '0%'
  },
  series: [{
    name: '异常频率',
    type: 'heatmap',
    data: [
      [0, 0, 5], [1, 0, 7], [2, 0, 3],
      [0, 1, 1], [1, 1, 2], [2, 1, 4],
      [0, 2, 10], [1, 2, 1], [2, 2, 0], // 异常点
      [0, 3, 1], [1, 3, 1], [2, 3, 3],
      [0, 4, 2], [1, 4, 6], [2, 4, 2]
    ],
    itemStyle: {
      borderColor: '#333'
    },
    emphasis: {
      itemStyle: {
        shadowBlur: 10,
        shadowColor: 'rgba(0, 0, 0, 0.5)'
      }
    }
  }]
};

动态异常检测方案

实时数据流监控

结合 WebSocket 实现实时异常检测:

// 模拟实时数据
function randomData() {
  now = new Date(+now + oneDay);
  value = Math.random() * 10;
  if(Math.random() > 0.95) value += 15; // 5%概率生成异常值
  return { name: now.toString(), value: [[now.getFullYear(), now.getMonth()+1, now.getDate()].join('/'), value] };
}

let data = [];
let now = new Date(2023, 0, 1);
let oneDay = 24 * 3600 * 1000;

for(let i = 0; i < 100; i++) data.push(randomData());

option = {
  title: { text: '动态异常检测' },
  tooltip: { trigger: 'axis' },
  xAxis: { type: 'time' },
  yAxis: { type: 'value', boundaryGap: [0, '100%'] },
  series: [{
    name: '模拟数据',
    type: 'line',
    showSymbol: false,
    data: data,
    markPoint: {
      data: [{
        type: 'max', name: '最大值'
      }, {
        type: 'min', name: '最小值'
      }],
      symbolSize: 60,
      label: {
        formatter: function(params) {
          return params.value > 15 ? '异常!' : params.name;
        },
        color: function(params) {
          return params.value > 15 ? '#ff0000' : '#333';
        }
      }
    }
  }]
};

// 模拟实时更新
setInterval(function() {
  for(let i = 0; i < 5; i++) data.shift();
  for(let i = 0; i < 5; i++) data.push(randomData());
  myChart.setOption({ series: [{ data: data }] });
}, 1000);

多维度联动分析

实现多视图联动的异常检测面板:

option = {
  tooltip: { trigger: 'axis' },
  legend: { data: ['CPU', '内存', '磁盘'] },
  grid: [
    { left: '10%', top: '10%', width: '80%', height: '25%' },
    { left: '10%', top: '40%', width: '35%', height: '25%' },
    { left: '55%', top: '40%', width: '35%', height: '25%' }
  ],
  xAxis: [
    { gridIndex: 0, type: 'category', data: ['1月','2月','3月','4月','5月','6月'] },
    { gridIndex: 1, type: 'category', data: ['1月','2月','3月','4月','5月','6月'] },
    { gridIndex: 2, type: 'category', data: ['1月','2月','3月','4月','5月','6月'] }
  ],
  yAxis: [
    { gridIndex: 0 },
    { gridIndex: 1 },
    { gridIndex: 2 }
  ],
  series: [
    {
      name: 'CPU',
      type: 'line',
      xAxisIndex: 0,
      yAxisIndex: 0,
      data: [65, 72, 83, 79, 95, 90],
      markArea: {
        silent: true,
        data: [[
          { xAxis: '4月' },
          { xAxis: '5月' }
        ]]
      }
    },
    {
      name: '内存',
      type: 'bar',
      xAxisIndex: 1,
      yAxisIndex: 1,
      data: [45, 52, 38, 60, 48, 33]
    },
    {
      name: '磁盘',
      type: 'scatter',
      xAxisIndex: 2,
      yAxisIndex: 2,
      symbolSize: function(data) {
        return data[1] * 2;
      },
      data: [
        ['1月', 25], ['2月', 40], ['3月', 10],
        ['4月', 35], ['5月', 70], ['6月', 20]  // 5月为异常点
      ],
      itemStyle: {
        color: function(params) {
          return params.data[1] > 60 ? '#ff0000' : '#5470c6';
        }
      }
    }
  ]
};

自定义视觉编码策略

阈值区间着色

在折线图中根据阈值范围着色不同区域:

option = {
  xAxis: { type: 'category', boundaryGap: false },
  yAxis: { type: 'value' },
  series: [{
    data: [120, 200, 150, 80, 70, 110, 130],
    type: 'line',
    areaStyle: {
      color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
        { offset: 0, color: 'rgba(255, 0, 0, 0.3)' },   // 高于阈值
        { offset: 0.5, color: 'rgba(255, 255, 0, 0.3)' }, // 警告阈值
        { offset: 1, color: 'rgba(0, 255, 0, 0.3)' }    // 正常范围
      ])
    },
    markLine: {
      silent: true,
      data: [{
        yAxis: 150,  // 警告阈值
        lineStyle: { color: '#ff0' }
      }, {
        yAxis: 100,  // 正常阈值
        lineStyle: { color: '#0f0' }
      }]
    }
  }]
};

异常点脉冲动画

为异常数据点添加特殊动画效果:

option = {
  xAxis: { data: ['A', 'B', 'C', 'D', 'E', 'F'] },
  yAxis: {},
  series: [{
    name: '数据',
    type: 'bar',
    data: [5, 20, 36, 10, 10, 20],
    itemStyle: {
      color: function(params) {
        return params.data > 30 ? {
          type: 'radial',
          x: 0.5,
          y: 0.5,
          r: 0.5,
          colorStops: [
            { offset: 0, color: '#ff0000' },
            { offset: 0.7, color: '#ff0000' },
            { offset: 1, color: 'transparent' }
          ]
        } : '#5470c6';
      }
    }
  }],
  graphic: [{
    type: 'circle',
    shape: { r: 0 },
    keyframeAnimation: {
      duration: 2000,
      loop: true,
      keyframes: [{
        percent: 0,
        shape: { r: 0 },
        style: { opacity: 0.8 }
      }, {
        percent: 1,
        shape: { r: 20 },
        style: { opacity: 0 }
      }]
    },
    position: [540, 100]  // 异常点位置
  }]
};

交互式异常分析

数据下钻与筛选

实现从概览到细节的异常分析流程:

// 第一级视图 - 概览
const overviewOption = {
  dataset: {
    dimensions: ['product', '2015', '2016', '2017', '2018', '2019', '2020'],
    source: [
      { product: '产品A', '2015': 43, '2016': 85, '2017': 93, '2018': 90, '2019': 106, '2020': 120 },
      { product: '产品B', '2015': 83, '2016': 73, '2017': 55, '2018': 89, '2019': 104, '2020': 30 }, // 异常
      { product: '产品C', '2015': 86, '2016': 65, '2017': 82, '2018': 96, '2019': 107, '2020': 101 }
    ]
  },
  tooltip: { trigger: 'axis' },
  legend: {},
  xAxis: { type: 'category' },
  yAxis: {},
  series: [
    { type: 'bar' },
    { type: 'bar' },
    { type: 'bar' }
  ]
};

// 第二级视图 - 详情
function getDetailOption(productName) {
  return {
    dataset: {
      dimensions: ['month', 'sales'],
      source: [
        { month: '1月', sales: Math.floor(Math.random() * 100) },
        { month: '2月', sales: Math.floor(Math.random() * 100) },
        // ...其他月份数据
        { month: '12月', sales: productName === '产品B' ? 5 : Math.floor(Math.random() * 100) } // 异常
      ]
    },
    title: { text: `${productName}月度销售详情` },
    xAxis: { type: 'category' },
    yAxis: {},
    series: [{
      type: 'line',
      markPoint: {
        data: [
          { type: 'max', name: '最大值' },
          { type: 'min', name: '最小值' }
        ]
      }
    }]
  };
}

// 点击事件处理
myChart.on('click', function(params) {
  if(params.componentType === 'series') {
    myChart.setOption(getDetailOption(params.seriesName));
  }
});

异常模式标注

在图表中直接标注异常模式:

option = {
  xAxis: { data: ['1月','2月','3月','4月','5月','6月','7月','8月','9月','10月','11月','12月'] },
  yAxis: {},
  series: [{
    name: '销售额',
    type: 'line',
    data: [120, 132, 101, 134, 290, 230, 210, 132, 101, 134, 90, 230],
    markPoint: {
      symbol: 'pin',
      symbolSize: 50,
      data: [
        { 
          coord: ['5月', 290],
          label: {
            formatter: '突增异常\n+150%',
            color: '#fff',
            fontSize: 14
          },
          itemStyle: { color: '#f00' }
        },
        {
          coord: ['11月', 90],
          label: {
            formatter: '骤降异常\n-60%',
            color: '#fff',
            fontSize: 14
          },
          itemStyle: { color: '#00f' }
        }
      ]
    }
  }]
};

我的名片

网名:~川~

岗位:console.log 调试员

坐标:重庆市-九龙坡区

邮箱:cc@qdcc.cn

沙漏人生

站点信息

  • 建站时间:2013/03/16
  • 本站运行
  • 文章数量
  • 总访问量
微信公众号
每次关注
都是向财富自由迈进的一步