spc x-bar 正态分布 echarts demo

使用echarts,elementUi,vue编写的spc分析的demo示例.

含x-bar和正态分布图,同一数据可以互转

在这里插入图片描述
在这里插入图片描述

chart.vue

<template>
  <div class="app-container">
    <el-row>
      <el-col :span="4" class="button-container">
        <el-button @click="redrawChart">重新绘制</el-button>
        <el-button type="warning" @click="analyzeData">重新解析数据并绘制</el-button>
        <el-button type="primary" @click="drawNormalChart">正态分布(X)</el-button>
        <el-button type="success" @click="showSpecDialog">更新SPEC(X)</el-button>
        <el-button type="info">计算cpk(X)</el-button>
        <el-button type="danger">危险按钮(X)</el-button>
      </el-col>
      <el-col :span="20">
        <div id="mainChart" style="height: 720px;width: 1080px;"/>
      </el-col>
    </el-row>
    <div>
      min:{{ dData.min.toFixed(3) }}
      max:{{ dData.min.toFixed(3) }}
      mean:{{ dData.min.toFixed(3) }}
      std:{{ dData.min.toFixed(3) }}
    </div>
    <div>
      说明
      1.x-bar等图的上线边界,计算上下边界,如果数据过于集中,自动图表缩放会导致usl甚至是ucl超出y轴范围,不能正常绘制,那么需要手动计算上下边界<br/>
      上边界取max值和usl+0.5*(usl-ucl)更大的那个<br/>
      下边界取min值和lsl-0.5*(lcl-lsl)更小的那个<br/>
      为避免出现小数位数过多/精度不足 取3位小数<br/>
      2.关闭SPEC弹框时由于数据已经被更新,所以在关闭弹框时间上直接绑定了重绘事件.
      但是由于上下边界是在解析数据阶段完成的,所以不会重新解析上下边界
    </div>
    <el-dialog title="更新SPEC" :visible.sync="visibleSpecDialog" width="800px" top="5vh" @closed="onSpecDialogClose" append-to-body>
      <el-form ref="form" :model="dData" label-width="200px">
        <el-form-item label="usl">
          <el-input v-model="dData.usl"/>
        </el-form-item>
        <el-form-item label="ucl">
          <el-input v-model="dData.ucl"/>
        </el-form-item>
        <el-form-item label="lcl">
          <el-input v-model="dData.lcl"/>
        </el-form-item>
        <el-form-item label="lsl">
          <el-input v-model="dData.lsl"/>
        </el-form-item>
      </el-form>
    </el-dialog>
  </div>
</template>

<script>
import * as echarts from "echarts";
import * as utils from './utils';

//定义显示的颜色
let red="#FF0000"
let yellow="#CCCC00"
let green="#009000"

export default {
  data() {
    //参数定义
    return {
      //主chart实例对象
      mainChart: {},
      //从服务器查询数据参数对象
      queryParams: {},
      //从服务器获取的原始数据(originalData)
      oData: {
        usl: 0,
        ucl: 0,
        cl: 0,
        lcl: 0,
        lsl: 0,
        dataList: []
      },
      //预定义维度数组,注意顺序,不要轻易改变,注意需要调整analyzeData的转二维数组的内容
      columns: ["dataTime", "paramValue", "remark"],
      //绘制图需要的数据格式,(drawData)
      dData: {
        //控制参数
        usl: 0,
        ucl: 0,
        cl: 0,
        lcl: 0,
        lsl: 0,
        //计算参数
        min: 0,
        max: 0,
        mean: 0,
        std: 0,
        upperY: 0,
        lowerY: 0,
        //仅提取paramValue作为值数组
        valueData: [],
        //x-barData 数据格式,就是二维数组
        xBarData: [],
        //正态分布数据格式
        normalData: {
          //正态分布前后距离
          dataRangeMinOP: 1,
          dataRangeMaxOP: 1.1,
          //组间距
          interval: 1,
          // 这3个就不构建datasource来处理了,直接用好了
          // 构建离散值x轴
          xAxis: [],
          // 构建柱状y轴
          barYaxis: [],
          // 构建线性y轴
          lineYaxis: []
        }
      },
      // 当前图表类型 1.XR 2.XS 3.WR 4.ZT FIXME
      showChartType: 1,
      //显示更新SPEC弹框标记
      visibleSpecDialog: false
    };
  },
  mounted() {
    this.init();
  },
  methods: {
    /**
      * 初始化方法
     * 调用过程如下:
     * init->queryData->analyzeData->redrawChart->createOption->this.chart.setOption
     */
    init() {
      //从dom加载echarts对象
      let chartDom = document.getElementById("mainChart");
      this.chart = echarts.init(chartDom);
      this.queryData();
    },
    /**
     * 从服务器获取原始数据
     * 实际参数:this.queryParams.... 返回结果到this.oData
     * 回调触发redrawChart
     */
    queryData() {
      this.oData.dataList = []

      //模拟写入数据
      for (let n = 0; n < 100; n++) {
        this.oData.dataList.push({
          dataTime: n + ":00",
          paramValue: 30 + Math.random() * 30,
          remark: (Math.random() * 20).toFixed(3)
        });
      }
      this.oData.usl = 55;
      this.oData.ucl = 50;
      this.oData.cl = 45;
      this.oData.lcl = 40;
      this.oData.lsl = 35;

      //解析原始为图表需要的数据
      this.analyzeData();
    },
    /**
     * 绘制,或重新绘制主chart图
     */
    redrawChart() {
      //清除图表
      this.chart.clear()
      //创建option并绘制
      let option = this.createOption();
      this.chart.setOption(option);
      //弹框说明
      this.$message.success("绘制图表成功!");
    },
    drawNormalChart() {
      if (this.showChartType === 1) {
        this.showChartType = 4;
      } else {
        this.showChartType = 1;
      }
      this.redrawChart();
    },
    showSpecDialog() {
      this.visibleSpecDialog = true;
    },
    //Spec弹框被关闭
    onSpecDialogClose() {
      this.redrawChart();
    },
    /**
     * 将原始数据解析为x-bar等图需要的格式
     * 计算mean,std.,cpk..等数据返回
     * 实际参数:this.oData.... 返回结果到this.dData
     */
    analyzeData() {
      //copy基础数据
      this.dData.usl = this.oData.usl;
      this.dData.ucl = this.oData.ucl;
      this.dData.cl = this.oData.cl;
      this.dData.lcl = this.oData.lcl;
      this.dData.lsl = this.oData.lsl;

      //仅提取paramValue作为值数组
      this.dData.valueData = this.oData.dataList.map(obj => obj.paramValue);
      //计算其他数据,最大最小cpk什么的
      this.dData.min = Math.min(...this.dData.valueData);
      this.dData.max = Math.max(...this.dData.valueData);
      this.dData.mean = this.dData.valueData.reduce((sum, val) => sum + val, 0) / this.dData.valueData.length;
      this.dData.std = utils.getStd(this.dData.valueData, this.dData.mean)

      //计算上下边界,如果数据过于集中,自动图表缩放会导致usl甚至是ucl超出y轴范围,不能正常绘制,那么需要手动计算上下边界
      //取max值和usl+0.5*(usl-ucl)更大的那个
      //取min值和lsl-0.5*(lcl-lsl)更小的那个
      this.dData.upperY = Math.max(this.dData.usl + 0.5 * (this.dData.usl - this.dData.ucl), this.dData.max).toFixed(3)
      this.dData.lowerY = Math.min(this.dData.lsl - 0.5 * (this.dData.lcl - this.dData.lsl), this.dData.min).toFixed(3)

      // 转x-bar需要数据
      // 对象数组转二维数组
      this.dData.xBarData = []
      this.dData.xBarData = this.oData.dataList.map(obj => [obj.dataTime, obj.paramValue, obj.remark]);

      // 转正态分布数据
      // 构建x轴
      let start = this.dData.min - this.dData.normalData.dataRangeMinOP;
      let end = this.dData.max + this.dData.normalData.dataRangeMaxOP;
      // 计算区间数量
      let numIntervals = Math.ceil((end - start) / this.dData.normalData.interval);
      // 构建离散值x轴
      let xAxis = [];
      for (let i = start; i <= end; i = i + this.dData.normalData.interval) {
        let str = i.toFixed(1).toString();
        xAxis.push(str);
      }
      this.dData.normalData.xAxis = xAxis;
      // 构建柱状y轴,遍历数组并计算频数
      let barYaxis = new Array(numIntervals).fill(0);
      this.dData.valueData.forEach((value) => {
        if (value >= start && value <= end) {
          // 找到值所在的区间
          let intervalIndex = Math.floor((value - start) / this.dData.normalData.interval);
          // 增加该区间的频数
          barYaxis[intervalIndex]++;
        }
      });
      this.dData.normalData.barYaxis = barYaxis;
      // 构建线性y轴
      this.dData.normalData.lineYaxis = utils.fxNormalDistribution(xAxis, this.dData.std, this.dData.mean);

      this.redrawChart();
    },
    /**
     * 构建图图表参数
     * @returns
     */
    createOption() {
      //内部匿名方法无法访问到this,用这个处理,下面都采用that
      let that = this;
      //option
      let option = {};
      //正态分布
      if (this.showChartType === 4) {
        //定义实际数据的频数柱状图
        let barDataSet = {
          type: "bar",
          smooth: true,
          yAxisIndex: 0,
          areaStyle: {
            opacity: 0,
          },
          data: that.dData.normalData.barYaxis,
          name: "实际分布频数",
          label: {
            formatter: "{c} %",
            show: false, //默认显示
            position: "top", //在上方显示
            textStyle: {
              //数值样式
              fontSize: 16,
            },
          },
        };
        //计算实际数据的正态分布图
        let lineDataSet = {
          type: "line",
          smooth: true,
          yAxisIndex: 1,
          areaStyle: {
            opacity: 0,
          },
          data: that.dData.normalData.lineYaxis,
          name: "实际正态分布",
          label: {
            formatter: "{c} %",
            show: false, //开启显示
            position: "top", //在上方显示
            textStyle: {
              //数值样式
              fontSize: 16,
            },
          },
        };

        option = {
          title: {
            text: 'SPC',
          },
          //提示框组件
          tooltip: {
            trigger: "axis",
            axisPointer: {
              type: "shadow",
            },
          },
          xAxis: {
            boundaryGap: true,
            type: "category",
            data: that.dData.normalData.xAxis,
          },
          //定义y轴
          yAxis: [{
            type: "value",
          }, {
            type: "value",
          }],
          series: [barDataSet, lineDataSet],
        };
      }
      //x-bar
      else {
        option = {
          title: {
            text: 'SPC',
          },
          tooltip: {
            trigger: 'axis',
            //轴数据指示
            axisPointer: {
              type: 'cross'
            },
          },
          xAxis: {
            type: 'category'
          },
          yAxis: {
            type: 'value',
            max: that.dData.upperY,
            min: that.dData.lowerY
          },
          dataset: [
            {
              //定义数据字段
              dimensions: [{name: "dataTime", type: 'ordinal'}, "paramValue", "remark"],
              //定义数据内容
              source: that.dData.xBarData
            },
          ],
          series: [
            {
              name: 'Dow-Jones index',
              type: 'line',
              //密集点数过多是否显示
              showAllSymbol: true,
              //定义xy轴取数据那一列值
              encode: {
                x: 'dataTime',
                y: 'paramValue',
                tooltip: ["paramValue", "dataTime", "remark"],
              },
              //定义点样式,依据数据定义点样式以及大小颜色
              symbol: function (params) {
                if (params[1] > that.dData.ucl || params[1] < that.dData.lcl) {
                  if (params[1] > that.dData.usl || params[1] < that.dData.lsl) {
                    return 'triangle';
                  }
                  return 'circle';
                } else {
                  return 'emptyCircle';
                }
              },
              symbolSize: function (params) {
                if (params[1] > that.dData.ucl || params[1] < that.dData.lcl) {
                  if (params[1] > that.dData.usl || params[1] < that.dData.lsl) {
                    return 10;
                  }
                  return 9;
                } else {
                  return 8;
                }
              },
              itemStyle: {
                color: function (params) {
                  if (params.data[1] > that.dData.ucl || params.data[1]< that.dData.lcl) {
                    if (params.data[1] > that.dData.usl || params.data[1] < that.dData.lsl) {
                      return red;
                    }
                    return yellow;
                  } else {
                    return green;
                  }
                }
              },
              //定义规格线
              markLine: {
                silent: true,
                symbol: 'none',
                data: [
                  {
                    name: 'USL',
                    yAxis: that.dData.usl,
                    lineStyle: {color: red},
                    label: {color: red, formatter: 'USL:' + that.dData.usl, fontSize: 10}
                  },
                  {
                    name: 'UCL',
                    yAxis: that.dData.ucl,
                    lineStyle: {color: yellow},
                    label: {color: yellow, formatter: 'UCL:' + that.dData.ucl, fontSize: 10}
                  },

                  {
                    name: 'CL',
                    yAxis: that.dData.cl,
                    lineStyle: {color: green},
                    label: {color: green, formatter: 'CL:' + that.dData.cl, fontSize: 10}
                  },
                  {
                    name: 'LCL',
                    yAxis: that.dData.lcl,
                    lineStyle: {color: yellow},
                    label: {color: yellow, formatter: 'LCL:' + that.dData.lcl, fontSize: 10}
                  },
                  {
                    name: 'LSL',
                    yAxis: that.dData.lsl,
                    lineStyle: {color: red},
                    label: {color: red, formatter: 'LSL:' + that.dData.lsl, fontSize: 10}
                  }
                ]
              }
            }
          ]
        };
      }
      return option;
    }
  },

};
</script>

<style scoped>
.button-container {
  display: grid;
  grid-template-columns: 1fr; /* 单列 */
  grid-auto-rows: minmax(auto, auto); /* 自动行高 */
  row-gap: 10px; /* 行间距 */
  /* 可以根据需要添加更多样式 */
}

.button-container .el-button {
  margin-right: 10px;
  margin-left: 10px;
}
</style>


utils.js

//计算正态曲线
export function fxNormalDistribution(array, std, mean) {
  let valueList = [];
  for (let i = 0; i < array.length; i++) {
    let ND =
      Math.sqrt(2 * Math.PI) *
      std *
      Math.pow(
        Math.E,
        -(Math.pow(array[i] - mean, 2) / (2 * Math.pow(std, 2)))
      );
    valueList.push(ND.toFixed(3));
  }
  return valueList;
}

//计算标准差
export function getStd(data, mean) {
  let sumXY = function (x, y) {
    return Number(x) + Number(y);
  };
  let square = function (x) {
    return Number(x) * Number(x);
  };
  let deviations = data.map(function (x) {
    return x - mean;
  });
  return Math.sqrt(deviations.map(square).reduce(sumXY) / (data.length - 1));
}


//对有序数组求中位数
export function getMedianSorted(arr) {
  // 获取数组长度
  let len = arr.length;

  // 如果没有元素,返回undefined或你可以返回其他合适的值
  if (len === 0) {
    return undefined;
  }

  // 如果只有一个元素,那么它就是中位数
  if (len === 1) {
    return arr[0];
  }

  // 如果数组长度是奇数,返回中间的数
  if (len % 2 === 1) {
    return arr[Math.floor(len / 2)];
  }

  // 如果数组长度是偶数,返回中间两个数的平均值
  else {
    let mid1 = arr[len / 2 - 1];
    let mid2 = arr[len / 2];
    return (mid1 + mid2) / 2.0;
  }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/463243.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

C++之类和对象(3)

目录 1. 再谈构造函数 1.1 构造函数体赋值 1.2 初始化列表 1.3 explicit 2. static成员 2.1 概念 3. 友元 3.1 友元函数 3.2 友元类 4. 内部类 5. 匿名对象 6. 拷贝对象时编译器做出的优化 1. 再谈构造函数 1.1 构造函数体赋值 class Date { public:Date(int year2024…

【Miniconda】基于conda避免运行多个PyTorch项目时发生版本冲突

【Miniconda】基于conda避免运行多个PyTorch项目时发生版本冲突 &#x1f308; 个人主页&#xff1a;高斯小哥 &#x1f525; 高质量专栏&#xff1a;Matplotlib之旅&#xff1a;零基础精通数据可视化、Python基础【高质量合集】、PyTorch零基础入门教程&#x1f448; 希望得到…

Day39:安全开发-JavaEE应用SpringBoot框架Actuator监控泄漏Swagger自动化

目录 SpringBoot-监控系统-Actuator SpringBoot-接口系统-Swagger 思维导图 Java知识点&#xff1a; 功能&#xff1a;数据库操作&#xff0c;文件操作&#xff0c;序列化数据&#xff0c;身份验证&#xff0c;框架开发&#xff0c;第三方组件使用等. 框架库&#xff1a;MyB…

十五、自回归(AutoRegressive)和自编码(AutoEncoding)语言模型

参考自回归语言模型&#xff08;AR&#xff09;和自编码语言模型&#xff08;AE&#xff09; 1 自回归语言模型&#xff08; AR&#xff09; 自回归语言模型&#xff08;AR&#xff09;就是根据上文内容&#xff08;或下文内容&#xff09;预测下一个&#xff08;或前一个&…

由浅到深认识C语言(13):共用体

该文章Github地址&#xff1a;https://github.com/AntonyCheng/c-notes 在此介绍一下作者开源的SpringBoot项目初始化模板&#xff08;Github仓库地址&#xff1a;https://github.com/AntonyCheng/spring-boot-init-template & CSDN文章地址&#xff1a;https://blog.csdn…

Unity Live Capture 中实现面部捕捉同步模型动画

Unity Face Capture 是一个强大的工具&#xff0c;可以帮助你快速轻松地将真实人脸表情捕捉到数字模型中。在本文中&#xff0c;我们将介绍如何在 Unity Face Capture 中实现面部捕捉同步模型动画。 安装 |实时捕获 |4.0.0 (unity3d.com) 安装软件插件 安装 Live Capture 软件…

(一)Neo4j下载安装以及初次使用

&#xff08;一&#xff09;下载 官网地址&#xff1a;Neo4j Graph Database & AnamConnect data as its stored with Neo4j. Perform powerful, complex queries at scale and speed with our graph data platform.https://neo4j.com/ &#xff08;二&#xff09;安装并配…

JavaWeb--HTML

一&#xff1a;HTML简介 *HTML是一门语言&#xff0c;所有的网页都是用HTML这门语言编写出来的&#xff1b; *HTML&#xff1a;超文本标记语言&#xff1b; 超文本&#xff1a;超越了文本的限制&#xff0c;比普通文本更强大。除了文字信息&#xff0c;还能定义图片&#xff…

Java NIO浅析

NIO&#xff08;Non-blocking I/O&#xff0c;在Java领域&#xff0c;也称为New I/O&#xff09;&#xff0c;是一种同步非阻塞的I/O模型&#xff0c;也是I/O多路复用的基础&#xff0c;已经被越来越多地应用到大型应用服务器&#xff0c;成为解决高并发与大量连接、I/O处理问题…

linux上MySQL的安装

(1)解压安装包 tar -xzvf mysql-5.7.33-linux-glibc2.12-x86_64.tar.gz mv mysql-5.7.33-linux-glibc2.12-x86_64 /usr/local/mysql(2)创建数据目录 [roothecs-161929 3306]# mkdir -p /data/mysql/3306/data [roothecs-161929 3306]# mkdir -p /data/mysql/3306/binlog [roo…

章鱼网络 Community Call #19|​开启与 Eigenlayer 的合作

香港时间2024年3月8日12点&#xff0c;章鱼网络举行第19期 Community Call。 在过去的一个月&#xff0c;章鱼网络在成功完成 $NEAR Restaking 功能的安全审计之后&#xff0c;一直在稳步吸引关注。事实上&#xff0c;在整个行业中&#xff0c;我们是极少数已经推出 Restaking …

哔哩哔哩后端Java一面

前言 作者&#xff1a;晓宜 个人简介&#xff1a;互联网大厂Java准入职&#xff0c;阿里云专家博主&#xff0c;csdn后端优质创作者&#xff0c;算法爱好者 最近各大公司的春招和实习招聘都开始了&#xff0c;这里分享下去年面试B站的的一些问题&#xff0c;希望对大家有所帮助…

STM32中MicroLIB的关闭为什么会导致卡死----解析

STM32MicroLIB 大家好我是 MHZ 。最近又开始往回捡单片机的知识了~ 之前大学的时候都没用过 STM 的 CubeMX&#xff0c;这会拿来用着感觉很方便啊~ 果然科技在进步&#xff01; 在开发使用 Keil 对 STM32 进行开发的时候在会有一个叫做 MicroLIB 的选项。 这个的具体原因我搜…

ros、c++基于类的编程基础

基于class的编程结构&#xff0c;中间穿插ros的话题发布机制。 首先建立功能包&#xff1a; catkin_create_pkg control geometry_msgs message_generation message_runtime nav_msgs roscpp rospy std_msgs以上依赖基本上是大多数的ros消息所需要的依赖了。 然后确定我们的…

科研绘图一:箱线图(添加贝赛尔曲线)

R语言绘图系列—箱线图贝赛尔曲线 &#xff08;一&#xff09;: 科研绘图一&#xff1a;箱线图&#xff08;添加贝赛尔曲线&#xff09; 文章目录 R语言绘图系列---箱线图贝赛尔曲线&#xff08;一&#xff09;: 科研绘图一&#xff1a;箱线图&#xff08;添加贝赛尔曲线&…

pytorch CV入门 - 汇总

初次编辑&#xff1a;2024/2/14&#xff1b;最后编辑&#xff1a;2024/3/9 参考网站-微软教程&#xff1a;https://learn.microsoft.com/en-us/training/modules/intro-computer-vision-pytorch 更多的内容可以参考本作者其他专栏&#xff1a; Pytorch基础&#xff1a;https…

主干网络篇 | YOLOv8更换主干网络之ShuffleNetV2

前言&#xff1a;Hello大家好&#xff0c;我是小哥谈。ShuffleNetV2是一种轻量级的神经网络架构&#xff0c;用于图像分类和目标检测任务。它是ShuffleNet的改进版本&#xff0c;旨在提高模型的性能和效率。ShuffleNetV2相比于之前的版本&#xff0c;在保持模型轻量化的同时&am…

centos命令history设置记录10000行

今天在操作服务器的时候&#xff0c;用history查看操作记录的时候&#xff0c;发现只能查看10条&#xff0c;这样不行啊&#xff0c;我想查看所有人对服务器操作的命令。 [rootbogon ~]# history解决办法&#xff1a; #1、找到/etc/profile文件中的histsize 把10改成10000 […

机器学习周报第33周

目录 摘要Abstract一、文献阅读1.1 论文标题1.2 论文摘要1.3 论文背景1.4 过去研究1.5 论文介绍1.5.1 论文模型1.5.2 时空交互学习模块&#xff08;Spatiotemporal Interactive Learning Module&#xff09;1.5.3 动态图推理模块&#xff08;Dynamic Graph Inference Module&am…

ISIS接口认证实验简述

默认情况下&#xff0c;ISIS接口认证通过在ISIS协议数据单元&#xff08;PDU&#xff09;中添加认证字段&#xff0c;例如&#xff1a;一个密钥或密码&#xff0c;用于验证发送方的身份。 ISIS接口认证防止未经授权的设备加入到网络中&#xff0c;并确保邻居之间的通信是可信的…