Jelajahi Sumber

换毛高占比正态分布图

liling 1 hari lalu
induk
melakukan
2d6002451b
1 mengubah file dengan 143 tambahan dan 204 penghapusan
  1. 143 204
      src/views/calc/calcMaogao/index.vue

+ 143 - 204
src/views/calc/calcMaogao/index.vue

@@ -141,227 +141,166 @@
           }
           //正态分布图
           function showEcharts1(seriesValuedata){            
-    
-            let listData = [];
-            let xAxis = [];
-            seriesValuedata.forEach((item, index) => {
-                listData.push(item.num)
-            });
-
-            let objGroup = listData.reduce(function(obj, name) {
-                obj[name] = obj[name] ? ++obj[name] : 1;
-                return obj;
-            }, {});
-
-            let max = Math.max(...listData);
-            let min = Math.min(...listData);
-
-            //x轴最大最小前后范围
-            let dataRangeMinOP = 2;
-            let dataRangeMaXOP = 2.1;
-            //间距 ,X轴的步距 
-            let dataRangeOP = 0.1;
-            //小数点位数.这个要和数据精确到哪一位相匹配
-            let Xpiont = 1;
-
-            //处理x轴,把数据范围内的x轴求出来,并设置值轴没有的值为空,按顺序对应
-            for (let i = min - dataRangeMinOP; i <= max + dataRangeMaXOP; i += dataRangeOP) {
-                let str = i.toFixed(Xpiont).toString();
-                xAxis.push(str);
-                if (objGroup[str] == null) {
-                    objGroup[str] = 0;
-                } 
-            }
-            //结果不对,用下面这个 解决 0.0!=0,1.0!=1的问题
-           /* for (let i = min - dataRangeMinOP; i <= max + dataRangeMaXOP; i += dataRangeOP) {
-              let str = i.toFixed(Xpiont).toString();
-              xAxis.push(str);
-              if (objGroup[Number(str)] == null) {
-                objGroup[str] = 0;
-              }
-            }*/
-
-            let barYaxis = [];
-            Object.keys(objGroup).sort(function(a, b) {
-                return parseFloat(a) - parseFloat(b)
-            }).map(key => {
-                let num = Math.floor((objGroup[key] / listData.length * 100) * 100) / 100;
-                barYaxis.push(num)
-            })
-             
-            
-            function sum(array) {
-                let s = 0;
-                array.forEach(function(val, idx, arr) {
-                    s += Number(val);
-                }, 0);
-                return s;
-            };
-
-            //正太曲线计算的基本数据和方法
-            let avg = 0;
-            let stdev = 0;
-            avg = sum(listData) / listData.length;
-
-            let sumXY = function(x, y) {
-                return Number(x) + Number(y);
-            };
-            let square = function(x) {
-                return Number(x) * Number(x);
-            };
-            let mean = listData.reduce(sumXY) / listData.length;
-            let deviations = listData.map(function(x) {
-                return x - mean;
-            });
+            //处理图表数据
+            function getChartData(baseData, cityName) {
+                var data = {
+                    baseData: [],
+                    xAxisData: [],//x轴
+                    realData: [],//实际数值
+                    stdplotData: []//正态分布数值
+                };
+                var sumObj = {};//保存每个aqi数值的出现次数
+                baseData.forEach(v=>{ 
+            			var aqi = Number(v.num); 
+            			data.baseData.push(aqi);
+            			if(!sumObj[aqi]){ 
+            				sumObj[aqi] = 1;
+            			}else{ 
+            				sumObj[aqi]++; 
+            			}            
+                });
+                
+                
+                
+                //console.log(sumObj);
+                var stdObj = getBebeQ(data.baseData);
+                
+                var max = stdObj.max;
+                for(var i = 0; i <= max; i++){
+                    //console.log(sumObj[i]);
+                    data.xAxisData.push(i);
+                    data.realData.push(sumObj[i] || 0);
+                }
+                
+                var yArr = [];
+                
+                //console.log(stdObj);
+                var mean = Number(stdObj.avg);//均值
+                var stdev = stdObj.stdDev;//标准差
+                var x = data.xAxisData;
             
+                for (var j = 0; j < x.length; j++) {
+                    var res = fun(x[j], mean, stdev).toFixed(2);
+                    yArr.push(res);
             
-            stdev = Math.sqrt(deviations.map(square).reduce(sumXY) / (listData.length - 1));
-
-            //计算正太曲线
-            function NDjs(array) {
-                let NDarr = [];
-                for (let i = 0; i < array.length; i++) {
-                    let ND = (Math.sqrt(2 * Math.PI) * stdev) * Math.pow(Math.E, (-(Math.pow(array[i] - avg, 2) / (2 * Math.pow(stdev, 2)))));
-                    NDarr.push(ND);
                 }
-                return NDarr
+                
+                data.stdplotData = yArr;
+                                
+                return data;
             }
-            let lineYaxis = NDjs(xAxis)
-            
             
-            //配置项,本身项目是可以动态在页面配置修改这些属性的,贴到这里用了默认值
-            let opacityOption = 'off';
-            let opacity = 0.5;
-            if (opacityOption == 'off') {
-                opacity = 0;
-            }
-            let endPositionOption = 'all';
-            let endPositionPercentum = '';
-            let endPosition;
-            if (endPositionOption == 'all') {
-                endPosition = 100;
-            } else if (endPositionOption == 'third') {
-                endPosition = 29;
-            } else {
-                endPosition = endPositionPercentum;
+            //求均值和标准差
+            function getBebeQ(numbers, digit = 2) {
+                    // 修复js浮点数精度误差问题
+                    const formulaCalc = function formulaCalc(formula, digit) {
+                      let pow = Math.pow(10, digit);
+                      return parseInt(formula * pow, 10) / pow;
+                    };
+                    let len = numbers.length;
+                    let sum = (a, b) => formulaCalc(a + b, digit);
+                    let max = Math.max.apply(null, numbers);
+                    let min = Math.min.apply(null, numbers);
+                    // 平均值
+                    let avg = numbers.reduce(sum) / len;
+                    // 计算中位数
+                    // 将数值从大到小顺序排列好,赋值给新数组用于计算中位数
+                    let sequence = [].concat(numbers).sort((a,b) => b-a);
+                    let mid = len & 1 === 0 ?
+                      (sequence[len/2] + sequence[len/2+1]) / 2 :
+                      sequence[(len+1)/2];
+                    // 计算标准差
+                    // 所有数减去其平均值的平方和,再除以数组个数(或个数减一,即变异数)再把所得值开根号
+                    let stdDev = Math.sqrt(numbers.map(n=> (n-avg) * (n-avg)).reduce(sum) / len);
+                    return {
+                      max,
+                      min,
+                      avg: avg.toFixed(digit),
+                      mid: parseFloat(mid).toFixed(digit),
+                      stdDev : stdDev.toFixed(digit)
+                    }
             }
-
-            let persents = 'on';
-            let format1;
-            let format2;
-            if (persents == 'on') {
-                format1 = '{value} %'
-                format2 = '{c} %'
+            
+            //正态分布值
+            function fun(x, u, a) {
+                return (1 / Math.sqrt(2 * Math.PI) * a) * Math.exp(-1 * ((x - u) * (x - u)) / (2 * a * a));
             }
-
-            let data = [];
-            let lineDataSet = {
-                type: 'line',
-                smooth: true,
-                yAxisIndex: 1,
-                areaStyle: {
-                    opacity: opacity
-                },
-                data: lineYaxis,
-                name: '正太分布曲线',
-                itemStyle: {
-                    normal: {
-                        label: {
-                            formatter: format2,
-                            show: false, //开启显示
-                            position: 'top', //在上方显示
-                            textStyle: { //数值样式
-                                fontSize: 16
-                            }
-                        }
-                    }
+            
+            function addParam(arr, target) {
+                //是否是等于
+                var flag = false;
+                var target = parseFloat(target);
+                //最小
+                if (target < parseFloat(arr[0])) {
+                    arr.unshift(target.toString());
+                    return arr;
                 }
-            }
-            let barDataSet = {
-                type: 'bar',
-                smooth: true,
-                yAxisIndex: 0,
-                areaStyle: {
-                    opacity: opacity
-                },
-                data: barYaxis,
-                name: '实际分布',
-                itemStyle: {
-                    normal: {
-                        label: {
-                            formatter: format2,
-                            show: false, //开启显示
-                            position: 'top', //在上方显示
-                            textStyle: { //数值样式
-                                fontSize: 16
-                            }
-                        }
+            
+                //最大
+                if (target > parseFloat(arr[arr.length - 1])) {
+                    arr.push(target.toString());
+                    return arr;
+                }
+            
+                //中间
+                for (var i = 0; i < arr.length; i++) {
+                    if (parseFloat(arr[i]) > target) {
+                        if (arr[i - 1] == target)
+                            flag = true;
+                        break;
                     }
                 }
+                if (flag) {
+                    return arr;
+                } else {
+                    arr.splice(i, 0, target.toString());
+                    return arr;
+                }
             }
-            data.push(lineDataSet, barDataSet);
-
+            var data = getChartData(seriesValuedata);
+            
             let option = {
-                type: 'scroll',
-                title: {
-                    text: ''
+                "legend": {},
+                color: ['rgb(50, 255, 200)', '#f00'],
+                //"color": ["#78b4ff", "#f66bc7", "#2bcba7", "#ff8896", "#79c628", "#6c93ee", "#a9abff", "#f7a23f", "#27bae7", "#ff6d9d", "#cb79ff", "#f95b5a", "#ccaf27", "#38b99c", "#93d0ff", "#bd74e0", "#fd77da", "#dea700"],
+                "xAxis": {
+                    "name": "",
+                    "data": data.xAxisData
                 },
-                dataZoom: [{
-                        type: 'inside',
-                        show: false,
-                        xAxisIndex: [0],
-                        start: 0,
-                        end: endPosition,
-                        borderColor: '#F5A9D0',
-                        backgroundColor: '#F5A9D0'
+                "yAxis": [{
+                    "name": "次数"
+                },{
+                    name: '频率'
+                }],
+                "series": [
+                    {
+                        "name": "实际出现次数",
+                        "data": data.realData,
+                        "type": "bar",
+                        "smooth": true,
+                        /*"areaStyle": {
+                            "normal": {
+                                "color": "rgba(50, 255, 200, 0.5)"
+                            }
+                        }*/
                     },
                     {
-                        show: false,
-                        type: 'slider',
-                        xAxisIndex: [0],
-                        start: 0,
-                        end: endPosition
+                        "name": "正态分布",
+                        yAxisIndex: 1,
+                        "data": data.stdplotData,
+                        "type": "line",
+                        "smooth": true,
+                        /*"areaStyle": {
+                            "normal": {
+                                "color": "rgba(50, 255, 200, 0.5)"
+                            }
+                        }*/
                     }
                 ],
-                tooltip: {
-                    trigger: "item",
-                    axisPointer: {
-                        type: "shadow"
-                    },
-                    formatter:function(params){
-                      //console.log(params)
-                      var v = (params.value*1).toFixed(2)
-                      return `${params.name} ${params.seriesName}:${v}`
-                    }
-                },
-                legend: {
-                    data: ['正太分布曲线', '实际分布']
-                },
-                xAxis: {
-                    boundaryGap: false,
-                    type: 'category',
-                    data: xAxis
-                },
-                yAxis: [{
-                    type: 'value',
-                    axisLabel: {
-                        formatter: format1
-                    }
-                }, {
-                    show: false,
-                    type: 'value',
-                    axisLabel: {
-                        formatter: '{value} %'
-                    }
-                }],
-                grid: [{
-                    left: '8%',
-                    top: '10%',
-                    width: '92%',
-                    height: '75%'
-                }],
-                series: data
-            };
+                "tooltip": {
+                    "trigger": "axis"
+                }
+            }
             let myChart = echarts.init(echatrs1.value)
             myChart.setOption(option);
           }