package line_feature import ( "errors" "github.com/shopspring/decimal" chartEdbMappingModel "hongze/hongze_yb/models/tables/chart_edb_mapping" edbDataModel "hongze/hongze_yb/models/tables/edb_data" "hongze/hongze_yb/services/chart" "hongze/hongze_yb/utils" "time" ) // LineFeatureDataResp 曲线图的一些数据返回 type LineFeatureDataResp struct { MaxData float64 MinData float64 LatestDate time.Time `description:"真实数据的最后日期"` EdbInfoCategoryType int ChartColor string ChartStyle string PredictChartColor string ChartType int ChartWidth float64 EdbName string EdbNameEn string Unit string UnitEn string IsAxis int DataList []edbDataModel.EdbDataList } // FrequencyDistributionResp 频率分布图数据 type FrequencyDistributionResp struct { LeftMinValue float64 LeftMaxValue float64 RightMinValue float64 RightMaxValue float64 DataList []FrequencyDistributionData } // FrequencyDistributionData 频率分布的值 type FrequencyDistributionData struct { Name string `description:"别名"` NameEn string `description:"英文别名"` Unit string `description:"单位"` UnitEn string `description:"单位别名"` Value interface{} `description:"每个指标的值"` Color string `description:"数据颜色"` IsAxis int `description:"1:左轴,0:右轴"` } // FrequencyDistributionYData 频率分布的实际数据 type FrequencyDistributionYData struct { X float64 Y float64 } // GetStandardDeviationData 获取标准差图表的指标数据 func GetStandardDeviationData(chartInfoId int, startDate, endDate string, mappingInfo *chartEdbMappingModel.ChartEdbInfoMapping, calculateValue int) (edbList []*chartEdbMappingModel.ChartEdbInfoMappingList, dataResp LineFeatureDataResp, sourceArr []string, err error, errMsg string) { edbList = make([]*chartEdbMappingModel.ChartEdbInfoMappingList, 0) // 指标对应的所有数据 _, edbList, sourceArr, err = chart.GetEdbDataMapList(chartInfoId, 1, `公历`, startDate, endDate, []*chartEdbMappingModel.ChartEdbInfoMapping{mappingInfo}, "") if err != nil { return } if len(edbList) != 1 { errMsg = `指标异常` err = errors.New(errMsg) return } edb := edbList[0] dataList := edb.DataList.([]*edbDataModel.EdbDataList) newDataList := make([]edbDataModel.EdbDataList, 0) lenData := len(dataList) var minVal, maxVal float64 if lenData >= calculateValue { tmpDataList := make([]float64, 0) for _, tmpData := range dataList { tmpDataList = append(tmpDataList, tmpData.Value) } for i := calculateValue; i <= lenData; i++ { tmpV := utils.CalculateStandardDeviation(tmpDataList[i-calculateValue : i]) tmpV, _ = decimal.NewFromFloat(tmpV).Round(4).Float64() newDataList = append(newDataList, edbDataModel.EdbDataList{ EdbDataId: i, EdbInfoId: edb.EdbInfoId, DataTime: dataList[i-1].DataTime, DataTimestamp: dataList[i-1].DataTimestamp, Value: tmpV, }) if tmpV > maxVal { maxVal = tmpV } if tmpV < minVal { minVal = tmpV } } } dataResp = LineFeatureDataResp{ MaxData: maxVal, MinData: minVal, LatestDate: edb.LatestDate, EdbInfoCategoryType: edb.EdbInfoCategoryType, ChartColor: `#00F`, ChartStyle: `spline`, PredictChartColor: `#00F`, ChartType: 0, ChartWidth: 3, EdbName: "标准差", EdbNameEn: "standard deviation", Unit: edb.Unit, UnitEn: edb.UnitEn, IsAxis: 1, DataList: newDataList, } return } // GetPercentileData 获取百分位图表的指标数据 func GetPercentileData(chartInfoId int, startDate, endDate string, mappingInfo *chartEdbMappingModel.ChartEdbInfoMapping, calculateValue int, calculateUnit string) (edbList []*chartEdbMappingModel.ChartEdbInfoMappingList, dataResp LineFeatureDataResp, sourceArr []string, err error, errMsg string) { edbList = make([]*chartEdbMappingModel.ChartEdbInfoMappingList, 0) moveUnitDays, ok := utils.FrequencyDaysMap[calculateUnit] if !ok { errMsg = `错误的周期` err = errors.New(errMsg) return } calculateDay := calculateValue * moveUnitDays // 指标对应的所有数据 _, edbList, sourceArr, err = chart.GetEdbDataMapList(chartInfoId, 1, `公历`, startDate, endDate, []*chartEdbMappingModel.ChartEdbInfoMapping{mappingInfo}, "") if err != nil { return } if len(edbList) != 1 { errMsg = `指标异常` err = errors.New(errMsg) return } edb := edbList[0] dataList := edb.DataList.([]*edbDataModel.EdbDataList) newDataList := make([]edbDataModel.EdbDataList, 0) var edbMinVal, edbMaxVal float64 dataMap := make(map[time.Time]float64, 0) for _, tmpData := range dataList { currDateTime, _ := time.ParseInLocation(utils.FormatDate, tmpData.DataTime, time.Local) dataMap[currDateTime] = tmpData.Value } //百分位:对所选指标滚动地取对应时间长度的数据值,取最大值Max,最小值Min,计算Max-Min,百分位=(现值-Min)/(Max-Min),Max=Min时不予计算。 for i, tmpData := range dataList { currDateTime, _ := time.ParseInLocation(utils.FormatDate, tmpData.DataTime, time.Local) maxVal := tmpData.Value minVal := tmpData.Value for k := 0; k < calculateDay; k++ { preVal, ok2 := dataMap[currDateTime.AddDate(0, 0, -k)] if ok2 { if preVal > maxVal { maxVal = preVal } if preVal < minVal { minVal = preVal } } } if maxVal == minVal { continue } //百分位=(现值-Min)/(Max-Min) tmpV := (tmpData.Value - minVal) / (maxVal - minVal) * 100 tmpV, _ = decimal.NewFromFloat(tmpV).Round(4).Float64() newDataList = append(newDataList, edbDataModel.EdbDataList{ EdbDataId: i, EdbInfoId: edb.EdbInfoId, DataTime: dataList[i].DataTime, DataTimestamp: dataList[i].DataTimestamp, Value: tmpV, }) if tmpV < edbMinVal { edbMinVal = tmpV } if tmpV > edbMaxVal { edbMaxVal = tmpV } } dataResp = LineFeatureDataResp{ MaxData: edbMaxVal, MinData: edbMinVal, LatestDate: edb.LatestDate, EdbInfoCategoryType: edb.EdbInfoCategoryType, ChartColor: `#00F`, ChartStyle: `spline`, PredictChartColor: `#00F`, ChartType: 0, ChartWidth: 3, EdbName: "百分位", EdbNameEn: "percentile", Unit: "%", UnitEn: "%", IsAxis: 1, DataList: newDataList, } return } // GetFrequencyDistributionData 获取频率分布的图表数据 func GetFrequencyDistributionData(chartInfoId int, mappingInfo *chartEdbMappingModel.ChartEdbInfoMapping, dateType, stepVal int, startDate, endDate string) (edbList []*chartEdbMappingModel.ChartEdbInfoMappingList, dataResp FrequencyDistributionResp, sourceArr []string, err error, errMsg string) { XDataList := make([]float64, 0) // 频度 Y1DataList := make([]FrequencyDistributionYData, 0) // 累计频率 Y2DataList := make([]FrequencyDistributionYData, 0) edbList = make([]*chartEdbMappingModel.ChartEdbInfoMappingList, 0) // 指标对应的所有数据 _, edbList, sourceArr, err = chart.GetEdbDataMapList(chartInfoId, 1, `公历`, startDate, endDate, []*chartEdbMappingModel.ChartEdbInfoMapping{mappingInfo}, "") if err != nil { return } if len(edbList) != 1 { err = errors.New("指标异常") return } startDateTime, _ := time.ParseInLocation(utils.FormatDate, startDate, time.Local) var endDateTime time.Time if endDate != `` { endDateTime, _ = time.ParseInLocation(utils.FormatDate, endDate, time.Local) } edb := edbList[0] dataList := edb.DataList.([]*edbDataModel.EdbDataList) if len(dataList) <= 0 { return } // 非自定义 if dateType != 8 { endDate = dataList[len(dataList)-1].DataTime endDateTime, err = time.ParseInLocation(utils.FormatDate, endDate, time.Local) if err != nil { return } //日期类型:1:最近3月;2:最近6月;3:最近1年;4:最近2年;5:最近3年;6:最近5年;7:最近10年,8:自定义时间 startDateTime = utils.GetDateByDateType2(dateType, endDateTime) startDate = startDateTime.Format(utils.FormatDate) newDataList := make([]*edbDataModel.EdbDataList, 0) for _, v := range dataList { tmpDataTime, tmpErr := time.ParseInLocation(utils.FormatDate, v.DataTime, time.Local) if tmpErr != nil { err = tmpErr return } if tmpDataTime.Equal(startDateTime) || tmpDataTime.After(startDateTime) { newDataList = append(newDataList, v) } } dataList = newDataList } maxVal := dataList[0].Value minVal := dataList[0].Value dataValMap := make(map[float64]int) total := 0 // 数据总量 for _, tmpData := range dataList { currDateTime, _ := time.ParseInLocation(utils.FormatDate, tmpData.DataTime, time.Local) if (currDateTime.Equal(startDateTime) || currDateTime.After(startDateTime)) && (endDateTime.IsZero() || currDateTime.Before(endDateTime)) { if maxVal < tmpData.Value { maxVal = tmpData.Value } if minVal > tmpData.Value { minVal = tmpData.Value } num, ok := dataValMap[tmpData.Value] if ok { dataValMap[tmpData.Value] = num + 1 } else { dataValMap[tmpData.Value] = 1 } total++ } } if total <= 0 { errMsg = `没有数据` err = errors.New(errMsg) return } // 最大最小值 向上/下取整 minVal = utils.GetFloorNewNum(minVal, 2) maxVal = utils.GetCeilNewNum(maxVal, 2) //间距 spacing, _ := (decimal.NewFromFloat(maxVal).Sub(decimal.NewFromFloat(minVal))).Div(decimal.NewFromInt(int64(stepVal))).Float64() distributionDataNumMap := make(map[float64]int) for i := 1; i <= stepVal; i++ { tmpMinVal, _ := decimal.NewFromFloat(minVal).Add((decimal.NewFromFloat(spacing)).Mul(decimal.NewFromInt(int64(i - 1)))).Float64() tmpMaxVal, _ := decimal.NewFromFloat(minVal).Add((decimal.NewFromFloat(spacing)).Mul(decimal.NewFromInt(int64(i)))).Float64() XDataList = append(XDataList, tmpMinVal) distributionDataNumMap[tmpMinVal] = 0 for tmpVal, num := range dataValMap { if tmpMinVal <= tmpVal { // 最后一期数据是要小于等于 if i == stepVal { if tmpVal <= tmpMaxVal { distributionDataNumMap[tmpMinVal] += num } } else { if tmpVal < tmpMaxVal { distributionDataNumMap[tmpMinVal] += num } } } } } var minFrequency, maxFrequency float64 tmpNum := 0 for k, tmpMinVal := range XDataList { // 数量 frequencyYNum := distributionDataNumMap[tmpMinVal] // 频率 tmpFrequency, _ := decimal.NewFromInt(int64(frequencyYNum)).Div(decimal.NewFromInt(int64(total))).Mul(decimal.NewFromInt(100)).Round(4).Float64() Y1DataList = append(Y1DataList, FrequencyDistributionYData{ X: tmpMinVal, Y: tmpFrequency, }) if k == 0 { minFrequency = tmpFrequency maxFrequency = tmpFrequency } else { if tmpFrequency < minFrequency { minFrequency = tmpFrequency } if tmpFrequency > maxFrequency { maxFrequency = tmpFrequency } } // 累计数 tmpNum += frequencyYNum // 累计频率 tmpTotalFrequency, _ := decimal.NewFromInt(int64(tmpNum)).Div(decimal.NewFromInt(int64(total))).Mul(decimal.NewFromInt(100)).Round(4).Float64() Y2DataList = append(Y2DataList, FrequencyDistributionYData{ X: tmpMinVal, Y: tmpTotalFrequency, }) } newDataList := []FrequencyDistributionData{ { Name: "频率", NameEn: "Frequency", Unit: "%", UnitEn: "%", Value: Y1DataList, Color: "#00F", IsAxis: 1, }, { Name: "累计频率", NameEn: "Total Frequency", Unit: "%", UnitEn: "%", Value: Y2DataList, Color: "#F00", IsAxis: 0, }, } edbList[0].DataList = nil dataResp = FrequencyDistributionResp{ LeftMinValue: minFrequency, LeftMaxValue: maxFrequency, RightMinValue: 0, RightMaxValue: 100, DataList: newDataList, } return }