chart_info.go 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352
  1. package line_equation
  2. import (
  3. "errors"
  4. "eta/eta_chart_lib/models"
  5. "eta/eta_chart_lib/models/data_manage/line_equation/request"
  6. "eta/eta_chart_lib/services/data"
  7. "eta/eta_chart_lib/utils"
  8. "github.com/shopspring/decimal"
  9. "math"
  10. "time"
  11. )
  12. type LineEquationResp struct {
  13. AData LineEquationDataResp
  14. BData LineEquationDataResp
  15. R2Data LineEquationDataResp
  16. }
  17. type LineEquationDataResp struct {
  18. MaxData float64
  19. MinData float64
  20. LatestDate string `description:"真实数据的最后日期"`
  21. EdbInfoCategoryType int
  22. ChartColor string
  23. ChartStyle string
  24. PredictChartColor string
  25. ChartType int
  26. ChartWidth int
  27. EdbName string
  28. EdbNameEn string
  29. Unit string
  30. UnitEn string
  31. IsAxis int
  32. DataList []models.EdbDataList
  33. }
  34. // GetChartEdbData 获取图表数据
  35. func GetChartEdbData(chartInfoId int, lineChartInfoConfig request.LineChartInfoReq, getAData, getBData, getR2Data bool) (edbList []*models.ChartEdbInfoMapping, dataResp LineEquationResp, err error, errMsg string) {
  36. // 获取基本信息
  37. mappingList, startDate, endDate, err, errMsg := getConfigData(lineChartInfoConfig)
  38. if err != nil {
  39. return
  40. }
  41. xEdbInfoIdList := lineChartInfoConfig.XEdbInfoIdList
  42. yEdbInfoIdList := lineChartInfoConfig.YEdbInfoIdList
  43. aLineEquationDataResp := LineEquationDataResp{
  44. DataList: make([]models.EdbDataList, 0),
  45. MaxData: 0,
  46. MinData: 0,
  47. ChartColor: "#00f",
  48. ChartStyle: `spline`,
  49. PredictChartColor: `#00f`,
  50. ChartType: 0,
  51. ChartWidth: 3,
  52. EdbName: `弹性系数`,
  53. EdbNameEn: `elastic coefficient`,
  54. IsAxis: 1,
  55. }
  56. bLineEquationDataResp := LineEquationDataResp{
  57. DataList: make([]models.EdbDataList, 0),
  58. MaxData: 0,
  59. MinData: 0,
  60. ChartColor: "#00f",
  61. ChartStyle: `spline`,
  62. PredictChartColor: `#00f`,
  63. ChartType: 0,
  64. ChartWidth: 3,
  65. EdbName: `截距`,
  66. EdbNameEn: `intercept`,
  67. IsAxis: 1,
  68. }
  69. r2LineEquationDataResp := LineEquationDataResp{
  70. DataList: make([]models.EdbDataList, 0),
  71. MaxData: 0,
  72. MinData: 0,
  73. ChartColor: "#00f",
  74. ChartStyle: `spline`,
  75. PredictChartColor: `#00f`,
  76. ChartType: 0,
  77. ChartWidth: 3,
  78. EdbName: `相关系数`,
  79. EdbNameEn: `coefficient of association`,
  80. IsAxis: 1,
  81. }
  82. edbList = make([]*models.ChartEdbInfoMapping, 0)
  83. dataResp = LineEquationResp{
  84. AData: aLineEquationDataResp,
  85. BData: bLineEquationDataResp,
  86. R2Data: r2LineEquationDataResp,
  87. }
  88. var baseEdbInfo *models.ChartEdbInfoMapping
  89. // 获取确定以哪个指标的日期作为基准日期
  90. {
  91. var xEdbInfo, yEdbInfo *models.ChartEdbInfoMapping
  92. for _, v := range mappingList {
  93. if v.EdbInfoId == xEdbInfoIdList[0] {
  94. xEdbInfo = v
  95. } else if v.EdbInfoId == yEdbInfoIdList[0] {
  96. yEdbInfo = v
  97. }
  98. }
  99. if xEdbInfo == nil {
  100. errMsg = `X轴第一个指标异常`
  101. err = errors.New(errMsg)
  102. return
  103. }
  104. if yEdbInfo == nil {
  105. errMsg = `Y轴第一个指标异常`
  106. err = errors.New(errMsg)
  107. return
  108. }
  109. // 时间截面规则:按照什么频率来取不同的截面的问题。原则是:按照X轴和Y轴所选择的第一个指标(X和Y分别有一个第一个指标),两个指标中,以低频的那个作为基准。如果X轴和Y轴是同频的,那以Y轴第一个指标的为准。
  110. frequencyIntMap := map[string]int{
  111. "日度": 1,
  112. "周度": 2,
  113. "旬度": 3,
  114. "月度": 4,
  115. "季度": 5,
  116. "年度": 6,
  117. }
  118. // 如果x是高频 或者 x与y是同频的,那么就是Y轴的第一个指标为主
  119. if frequencyIntMap[xEdbInfo.Frequency] <= frequencyIntMap[yEdbInfo.Frequency] {
  120. baseEdbInfo = yEdbInfo
  121. } else {
  122. // 否则是X轴的第一个指标是低频
  123. baseEdbInfo = xEdbInfo
  124. }
  125. }
  126. // 指标对应的所有数据
  127. chartType := 1 //1:普通图,2:季节性图
  128. calendar := "公历"
  129. edbDataListMap, edbList, err := data.GetEdbDataMapList(chartInfoId, chartType, calendar, startDate, endDate, mappingList, "")
  130. if err != nil {
  131. return
  132. }
  133. // 获取所有的日期
  134. dateList := make([]string, 0)
  135. for _, v := range edbDataListMap[baseEdbInfo.EdbInfoId] {
  136. dateList = append(dateList, v.DataTime)
  137. }
  138. // 数据整理
  139. // [日期][A指标id:值,B指标id:值]
  140. dateEdbMap, err := handleData(baseEdbInfo.EdbInfoId, edbDataListMap)
  141. if err != nil {
  142. return
  143. }
  144. lenX := len(xEdbInfoIdList)
  145. var isNotAFirst, isNotBFirst, isNotR2First bool
  146. for i, date := range dateList {
  147. coordinateData := make([]utils.Coordinate, 0)
  148. for k := 0; k < lenX; k++ {
  149. xVal, ok1 := dateEdbMap[date][xEdbInfoIdList[k]]
  150. yVal, ok2 := dateEdbMap[date][yEdbInfoIdList[k]]
  151. if !ok1 || !ok2 {
  152. continue
  153. }
  154. tmpCoordinate1 := utils.Coordinate{
  155. X: xVal,
  156. Y: yVal,
  157. }
  158. coordinateData = append(coordinateData, tmpCoordinate1)
  159. }
  160. dataTime, _ := time.ParseInLocation(utils.FormatDate, date, time.Local)
  161. timestamp := dataTime.UnixNano() / 1e6
  162. // 只有存在两个坐标点的时候,才能去计算线性方程和R平方
  163. if len(coordinateData) >= 2 {
  164. a, b := utils.GetLinearResult(coordinateData)
  165. if !math.IsNaN(a) && !math.IsNaN(b) && !math.IsInf(a, 0) && !math.IsInf(b, 0) {
  166. if getAData {
  167. a, _ = decimal.NewFromFloat(a).Round(4).Float64()
  168. dataResp.AData.DataList = append(dataResp.AData.DataList, models.EdbDataList{
  169. EdbDataId: i,
  170. EdbInfoId: 0,
  171. DataTime: date,
  172. DataTimestamp: timestamp,
  173. Value: a,
  174. })
  175. if !isNotAFirst {
  176. dataResp.AData.MinData = a
  177. dataResp.AData.MaxData = a
  178. isNotAFirst = true
  179. }
  180. if dataResp.AData.MinData > a {
  181. dataResp.AData.MinData = a
  182. }
  183. if dataResp.AData.MaxData < a {
  184. dataResp.AData.MaxData = a
  185. }
  186. }
  187. if getBData {
  188. b, _ = decimal.NewFromFloat(b).Round(4).Float64()
  189. dataResp.BData.DataList = append(dataResp.BData.DataList, models.EdbDataList{
  190. EdbDataId: i,
  191. EdbInfoId: 0,
  192. DataTime: date,
  193. DataTimestamp: timestamp,
  194. Value: b,
  195. })
  196. if !isNotBFirst {
  197. dataResp.BData.MinData = b
  198. dataResp.BData.MaxData = b
  199. isNotBFirst = true
  200. }
  201. if dataResp.BData.MinData > b {
  202. dataResp.BData.MinData = b
  203. }
  204. if dataResp.BData.MaxData < b {
  205. dataResp.BData.MaxData = b
  206. }
  207. }
  208. }
  209. // 计算R平方
  210. if getR2Data {
  211. tmpVal := utils.CalculationDecisive(coordinateData)
  212. if math.IsNaN(tmpVal) || math.IsInf(tmpVal, 0) {
  213. continue
  214. }
  215. tmpVal, _ = decimal.NewFromFloat(tmpVal).Round(4).Float64()
  216. dataResp.R2Data.DataList = append(dataResp.R2Data.DataList, models.EdbDataList{
  217. EdbDataId: i,
  218. EdbInfoId: 0,
  219. DataTime: date,
  220. DataTimestamp: timestamp,
  221. Value: tmpVal,
  222. })
  223. if !isNotR2First {
  224. dataResp.R2Data.MinData = tmpVal
  225. dataResp.R2Data.MaxData = tmpVal
  226. isNotR2First = true
  227. }
  228. if dataResp.R2Data.MinData > tmpVal {
  229. dataResp.R2Data.MinData = tmpVal
  230. }
  231. if dataResp.R2Data.MaxData < tmpVal {
  232. dataResp.R2Data.MaxData = tmpVal
  233. }
  234. }
  235. }
  236. }
  237. dataResp.AData.LatestDate = baseEdbInfo.LatestDate
  238. dataResp.AData.EdbInfoCategoryType = baseEdbInfo.EdbInfoCategoryType
  239. dataResp.BData.LatestDate = baseEdbInfo.LatestDate
  240. dataResp.BData.EdbInfoCategoryType = baseEdbInfo.EdbInfoCategoryType
  241. dataResp.R2Data.LatestDate = baseEdbInfo.LatestDate
  242. dataResp.R2Data.EdbInfoCategoryType = baseEdbInfo.EdbInfoCategoryType
  243. return
  244. }
  245. // getConfigData 获取配置数据
  246. func getConfigData(lineChartInfoConfig request.LineChartInfoReq) (mappingList []*models.ChartEdbInfoMapping, startDate, endDate string, err error, errMsg string) {
  247. dateType := lineChartInfoConfig.DateType
  248. switch dateType {
  249. case 1:
  250. startDate = "2000-01-01"
  251. case 2:
  252. startDate = "2010-01-01"
  253. case 3:
  254. startDate = "2015-01-01"
  255. case 4:
  256. //startDate = strconv.Itoa(time.Now().Year()) + "-01-01"
  257. startDate = "2021-01-01"
  258. case 5:
  259. startDate = lineChartInfoConfig.StartDate + "-01"
  260. endDate = lineChartInfoConfig.EndDate + "-01"
  261. case 6:
  262. startDate = lineChartInfoConfig.StartDate + "-01"
  263. case 7:
  264. startDate = "2018-01-01"
  265. case 8:
  266. startDate = "2019-01-01"
  267. case 9:
  268. startDate = "2020-01-01"
  269. case 11:
  270. startDate = "2022-01-01"
  271. }
  272. //指标数据
  273. edbInfoIdList := make([]int, 0)
  274. {
  275. edbInfoIdMap := make(map[int]int, 0)
  276. for _, edbInfoId := range lineChartInfoConfig.XEdbInfoIdList {
  277. edbInfoIdMap[edbInfoId] = edbInfoId
  278. }
  279. for _, edbInfoId := range lineChartInfoConfig.YEdbInfoIdList {
  280. edbInfoIdMap[edbInfoId] = edbInfoId
  281. }
  282. for _, edbInfoId := range edbInfoIdMap {
  283. edbInfoIdList = append(edbInfoIdList, edbInfoId)
  284. }
  285. }
  286. mappingList, err = models.GetChartEdbMappingListByEdbInfoIdList(edbInfoIdList)
  287. if err != nil {
  288. errMsg = `获取失败`
  289. err = errors.New("获取图表,指标信息失败,Err:" + err.Error())
  290. return
  291. }
  292. return
  293. }
  294. // handleData 数据处理
  295. func handleData(baseEdbInfoId int, edbDataListMap map[int][]*models.EdbDataList) (dateEdbMap map[string]map[int]float64, err error) {
  296. dateEdbMap = make(map[string]map[int]float64) // [日期][A指标id:值,B指标id:值]
  297. for edbInfoId, edbDataList := range edbDataListMap {
  298. if edbInfoId != baseEdbInfoId {
  299. // 用上期的数据补充当期的数据处理
  300. handleDataMap := make(map[string]float64)
  301. err = models.HandleDataByPreviousData(edbDataList, handleDataMap)
  302. if err != nil {
  303. return
  304. }
  305. for date, val := range handleDataMap {
  306. item, ok := dateEdbMap[date]
  307. if ok {
  308. item[edbInfoId] = val
  309. } else {
  310. item = map[int]float64{
  311. edbInfoId: val,
  312. }
  313. }
  314. dateEdbMap[date] = item
  315. }
  316. } else {
  317. for _, edbData := range edbDataList {
  318. item, ok := dateEdbMap[edbData.DataTime]
  319. if ok {
  320. item[edbInfoId] = edbData.Value
  321. } else {
  322. item = map[int]float64{
  323. edbInfoId: edbData.Value,
  324. }
  325. }
  326. dateEdbMap[edbData.DataTime] = item
  327. }
  328. }
  329. }
  330. return
  331. }