chart_info.go 10 KB

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