|
@@ -0,0 +1,393 @@
|
|
|
+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, 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, `公历`, ``, ``, []*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, 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, `公历`, ``, ``, []*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
|
|
|
+}
|