123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352 |
- package line_equation
- import (
- "errors"
- "eta/eta_chart_lib/models"
- "eta/eta_chart_lib/models/data_manage/line_equation/request"
- "eta/eta_chart_lib/services/data"
- "eta/eta_chart_lib/utils"
- "github.com/shopspring/decimal"
- "math"
- "time"
- )
- type LineEquationResp struct {
- AData LineEquationDataResp
- BData LineEquationDataResp
- R2Data LineEquationDataResp
- }
- type LineEquationDataResp struct {
- MaxData float64
- MinData float64
- LatestDate string `description:"真实数据的最后日期"`
- EdbInfoCategoryType int
- ChartColor string
- ChartStyle string
- PredictChartColor string
- ChartType int
- ChartWidth int
- EdbName string
- EdbNameEn string
- Unit string
- UnitEn string
- IsAxis int
- DataList []models.EdbDataList
- }
- // GetChartEdbData 获取图表数据
- func GetChartEdbData(chartInfoId int, lineChartInfoConfig request.LineChartInfoReq, getAData, getBData, getR2Data bool) (edbList []*models.ChartEdbInfoMapping, dataResp LineEquationResp, err error, errMsg string) {
- // 获取基本信息
- mappingList, startDate, endDate, err, errMsg := getConfigData(lineChartInfoConfig)
- if err != nil {
- return
- }
- xEdbInfoIdList := lineChartInfoConfig.XEdbInfoIdList
- yEdbInfoIdList := lineChartInfoConfig.YEdbInfoIdList
- aLineEquationDataResp := LineEquationDataResp{
- DataList: make([]models.EdbDataList, 0),
- MaxData: 0,
- MinData: 0,
- ChartColor: "#00f",
- ChartStyle: `spline`,
- PredictChartColor: `#00f`,
- ChartType: 0,
- ChartWidth: 3,
- EdbName: `弹性系数`,
- EdbNameEn: `elastic coefficient`,
- IsAxis: 1,
- }
- bLineEquationDataResp := LineEquationDataResp{
- DataList: make([]models.EdbDataList, 0),
- MaxData: 0,
- MinData: 0,
- ChartColor: "#00f",
- ChartStyle: `spline`,
- PredictChartColor: `#00f`,
- ChartType: 0,
- ChartWidth: 3,
- EdbName: `截距`,
- EdbNameEn: `intercept`,
- IsAxis: 1,
- }
- r2LineEquationDataResp := LineEquationDataResp{
- DataList: make([]models.EdbDataList, 0),
- MaxData: 0,
- MinData: 0,
- ChartColor: "#00f",
- ChartStyle: `spline`,
- PredictChartColor: `#00f`,
- ChartType: 0,
- ChartWidth: 3,
- EdbName: `相关系数`,
- EdbNameEn: `coefficient of association`,
- IsAxis: 1,
- }
- edbList = make([]*models.ChartEdbInfoMapping, 0)
- dataResp = LineEquationResp{
- AData: aLineEquationDataResp,
- BData: bLineEquationDataResp,
- R2Data: r2LineEquationDataResp,
- }
- var baseEdbInfo *models.ChartEdbInfoMapping
- // 获取确定以哪个指标的日期作为基准日期
- {
- var xEdbInfo, yEdbInfo *models.ChartEdbInfoMapping
- for _, v := range mappingList {
- if v.EdbInfoId == xEdbInfoIdList[0] {
- xEdbInfo = v
- } else if v.EdbInfoId == yEdbInfoIdList[0] {
- yEdbInfo = v
- }
- }
- if xEdbInfo == nil {
- errMsg = `X轴第一个指标异常`
- err = errors.New(errMsg)
- return
- }
- if yEdbInfo == nil {
- errMsg = `Y轴第一个指标异常`
- err = errors.New(errMsg)
- return
- }
- // 时间截面规则:按照什么频率来取不同的截面的问题。原则是:按照X轴和Y轴所选择的第一个指标(X和Y分别有一个第一个指标),两个指标中,以低频的那个作为基准。如果X轴和Y轴是同频的,那以Y轴第一个指标的为准。
- frequencyIntMap := map[string]int{
- "日度": 1,
- "周度": 2,
- "旬度": 3,
- "月度": 4,
- "季度": 5,
- "年度": 6,
- }
- // 如果x是高频 或者 x与y是同频的,那么就是Y轴的第一个指标为主
- if frequencyIntMap[xEdbInfo.Frequency] <= frequencyIntMap[yEdbInfo.Frequency] {
- baseEdbInfo = yEdbInfo
- } else {
- // 否则是X轴的第一个指标是低频
- baseEdbInfo = xEdbInfo
- }
- }
- // 指标对应的所有数据
- chartType := 1 //1:普通图,2:季节性图
- calendar := "公历"
- edbDataListMap, edbList, err := data.GetEdbDataMapList(chartInfoId, chartType, calendar, startDate, endDate, mappingList, "")
- if err != nil {
- return
- }
- // 获取所有的日期
- dateList := make([]string, 0)
- for _, v := range edbDataListMap[baseEdbInfo.EdbInfoId] {
- dateList = append(dateList, v.DataTime)
- }
- // 数据整理
- // [日期][A指标id:值,B指标id:值]
- dateEdbMap, err := handleData(baseEdbInfo.EdbInfoId, edbDataListMap)
- if err != nil {
- return
- }
- lenX := len(xEdbInfoIdList)
- var isNotAFirst, isNotBFirst, isNotR2First bool
- for i, date := range dateList {
- coordinateData := make([]utils.Coordinate, 0)
- for k := 0; k < lenX; k++ {
- xVal, ok1 := dateEdbMap[date][xEdbInfoIdList[k]]
- yVal, ok2 := dateEdbMap[date][yEdbInfoIdList[k]]
- if !ok1 || !ok2 {
- continue
- }
- tmpCoordinate1 := utils.Coordinate{
- X: xVal,
- Y: yVal,
- }
- coordinateData = append(coordinateData, tmpCoordinate1)
- }
- dataTime, _ := time.ParseInLocation(utils.FormatDate, date, time.Local)
- timestamp := dataTime.UnixNano() / 1e6
- // 只有存在两个坐标点的时候,才能去计算线性方程和R平方
- if len(coordinateData) >= 2 {
- a, b := utils.GetLinearResult(coordinateData)
- if !math.IsNaN(a) && !math.IsNaN(b) && !math.IsInf(a, 0) && !math.IsInf(b, 0) {
- if getAData {
- a, _ = decimal.NewFromFloat(a).Round(4).Float64()
- dataResp.AData.DataList = append(dataResp.AData.DataList, models.EdbDataList{
- EdbDataId: i,
- EdbInfoId: 0,
- DataTime: date,
- DataTimestamp: timestamp,
- Value: a,
- })
- if !isNotAFirst {
- dataResp.AData.MinData = a
- dataResp.AData.MaxData = a
- isNotAFirst = true
- }
- if dataResp.AData.MinData > a {
- dataResp.AData.MinData = a
- }
- if dataResp.AData.MaxData < a {
- dataResp.AData.MaxData = a
- }
- }
- if getBData {
- b, _ = decimal.NewFromFloat(b).Round(4).Float64()
- dataResp.BData.DataList = append(dataResp.BData.DataList, models.EdbDataList{
- EdbDataId: i,
- EdbInfoId: 0,
- DataTime: date,
- DataTimestamp: timestamp,
- Value: b,
- })
- if !isNotBFirst {
- dataResp.BData.MinData = b
- dataResp.BData.MaxData = b
- isNotBFirst = true
- }
- if dataResp.BData.MinData > b {
- dataResp.BData.MinData = b
- }
- if dataResp.BData.MaxData < b {
- dataResp.BData.MaxData = b
- }
- }
- }
- // 计算R平方
- if getR2Data {
- tmpVal := utils.CalculationDecisive(coordinateData)
- if math.IsNaN(tmpVal) || math.IsInf(tmpVal, 0) {
- continue
- }
- tmpVal, _ = decimal.NewFromFloat(tmpVal).Round(4).Float64()
- dataResp.R2Data.DataList = append(dataResp.R2Data.DataList, models.EdbDataList{
- EdbDataId: i,
- EdbInfoId: 0,
- DataTime: date,
- DataTimestamp: timestamp,
- Value: tmpVal,
- })
- if !isNotR2First {
- dataResp.R2Data.MinData = tmpVal
- dataResp.R2Data.MaxData = tmpVal
- isNotR2First = true
- }
- if dataResp.R2Data.MinData > tmpVal {
- dataResp.R2Data.MinData = tmpVal
- }
- if dataResp.R2Data.MaxData < tmpVal {
- dataResp.R2Data.MaxData = tmpVal
- }
- }
- }
- }
- dataResp.AData.LatestDate = baseEdbInfo.LatestDate
- dataResp.AData.EdbInfoCategoryType = baseEdbInfo.EdbInfoCategoryType
- dataResp.BData.LatestDate = baseEdbInfo.LatestDate
- dataResp.BData.EdbInfoCategoryType = baseEdbInfo.EdbInfoCategoryType
- dataResp.R2Data.LatestDate = baseEdbInfo.LatestDate
- dataResp.R2Data.EdbInfoCategoryType = baseEdbInfo.EdbInfoCategoryType
- return
- }
- // getConfigData 获取配置数据
- func getConfigData(lineChartInfoConfig request.LineChartInfoReq) (mappingList []*models.ChartEdbInfoMapping, startDate, endDate string, err error, errMsg string) {
- dateType := lineChartInfoConfig.DateType
- switch dateType {
- case 1:
- startDate = "2000-01-01"
- case 2:
- startDate = "2010-01-01"
- case 3:
- startDate = "2015-01-01"
- case 4:
- //startDate = strconv.Itoa(time.Now().Year()) + "-01-01"
- startDate = "2021-01-01"
- case 5:
- startDate = lineChartInfoConfig.StartDate + "-01"
- endDate = lineChartInfoConfig.EndDate + "-01"
- case 6:
- startDate = lineChartInfoConfig.StartDate + "-01"
- case 7:
- startDate = "2018-01-01"
- case 8:
- startDate = "2019-01-01"
- case 9:
- startDate = "2020-01-01"
- case 11:
- startDate = "2022-01-01"
- }
- //指标数据
- edbInfoIdList := make([]int, 0)
- {
- edbInfoIdMap := make(map[int]int, 0)
- for _, edbInfoId := range lineChartInfoConfig.XEdbInfoIdList {
- edbInfoIdMap[edbInfoId] = edbInfoId
- }
- for _, edbInfoId := range lineChartInfoConfig.YEdbInfoIdList {
- edbInfoIdMap[edbInfoId] = edbInfoId
- }
- for _, edbInfoId := range edbInfoIdMap {
- edbInfoIdList = append(edbInfoIdList, edbInfoId)
- }
- }
- mappingList, err = models.GetChartEdbMappingListByEdbInfoIdList(edbInfoIdList)
- if err != nil {
- errMsg = `获取失败`
- err = errors.New("获取图表,指标信息失败,Err:" + err.Error())
- return
- }
- return
- }
- // handleData 数据处理
- func handleData(baseEdbInfoId int, edbDataListMap map[int][]*models.EdbDataList) (dateEdbMap map[string]map[int]float64, err error) {
- dateEdbMap = make(map[string]map[int]float64) // [日期][A指标id:值,B指标id:值]
- for edbInfoId, edbDataList := range edbDataListMap {
- if edbInfoId != baseEdbInfoId {
- // 用上期的数据补充当期的数据处理
- handleDataMap := make(map[string]float64)
- err = models.HandleDataByPreviousData(edbDataList, handleDataMap)
- if err != nil {
- return
- }
- for date, val := range handleDataMap {
- item, ok := dateEdbMap[date]
- if ok {
- item[edbInfoId] = val
- } else {
- item = map[int]float64{
- edbInfoId: val,
- }
- }
- dateEdbMap[date] = item
- }
- } else {
- for _, edbData := range edbDataList {
- item, ok := dateEdbMap[edbData.DataTime]
- if ok {
- item[edbInfoId] = edbData.Value
- } else {
- item = map[int]float64{
- edbInfoId: edbData.Value,
- }
- }
- dateEdbMap[edbData.DataTime] = item
- }
- }
- }
- return
- }
|