chart_info.go 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398
  1. package line_feature
  2. import (
  3. "errors"
  4. "eta/eta_chart_lib/models"
  5. "eta/eta_chart_lib/models/data_manage/line_feature/response"
  6. "eta/eta_chart_lib/services/data"
  7. "eta/eta_chart_lib/utils"
  8. "github.com/shopspring/decimal"
  9. "time"
  10. )
  11. // GetStandardDeviationData 获取标准差图表的指标数据
  12. func GetStandardDeviationData(chartInfoId int, startDate, endDate string, mappingInfo *models.ChartEdbInfoMapping, calculateValue int) (edbList []*models.ChartEdbInfoMapping, dataResp response.LineFeatureDataResp, err error, errMsg string) {
  13. edbList = make([]*models.ChartEdbInfoMapping, 0)
  14. // 指标对应的所有数据
  15. _, edbList, err = data.GetEdbDataMapList(chartInfoId, 1, `公历`, startDate, endDate, []*models.ChartEdbInfoMapping{mappingInfo}, "")
  16. if err != nil {
  17. return
  18. }
  19. if len(edbList) != 1 {
  20. errMsg = `指标异常`
  21. err = errors.New(errMsg)
  22. return
  23. }
  24. edb := edbList[0]
  25. dataList := edb.DataList.([]*models.EdbDataList)
  26. newDataList := make([]models.EdbDataList, 0)
  27. lenData := len(dataList)
  28. var minVal, maxVal float64
  29. if lenData >= calculateValue {
  30. tmpDataList := make([]float64, 0)
  31. for _, tmpData := range dataList {
  32. tmpDataList = append(tmpDataList, tmpData.Value)
  33. }
  34. for i := calculateValue; i <= lenData; i++ {
  35. tmpV := utils.CalculateStandardDeviation(tmpDataList[i-calculateValue : i])
  36. tmpV, _ = decimal.NewFromFloat(tmpV).Round(4).Float64()
  37. newDataList = append(newDataList, models.EdbDataList{
  38. EdbDataId: i,
  39. EdbInfoId: edb.EdbInfoId,
  40. DataTime: dataList[i-1].DataTime,
  41. DataTimestamp: dataList[i-1].DataTimestamp,
  42. Value: tmpV,
  43. })
  44. if tmpV > maxVal {
  45. maxVal = tmpV
  46. }
  47. if tmpV < minVal {
  48. minVal = tmpV
  49. }
  50. }
  51. }
  52. dataResp = response.LineFeatureDataResp{
  53. MaxData: maxVal,
  54. MinData: minVal,
  55. LatestDate: edb.LatestDate,
  56. EdbInfoCategoryType: edb.EdbInfoCategoryType,
  57. ChartColor: `#00F`,
  58. ChartStyle: `spline`,
  59. PredictChartColor: `#00F`,
  60. ChartType: 0,
  61. ChartWidth: 3,
  62. EdbName: "标准差",
  63. EdbNameEn: "standard deviation",
  64. Unit: edb.Unit,
  65. UnitEn: edb.UnitEn,
  66. IsAxis: 1,
  67. DataList: newDataList,
  68. }
  69. return
  70. }
  71. // GetPercentileData 获取百分位图表的指标数据
  72. func GetPercentileData(chartInfoId int, startDate, endDate string, mappingInfo *models.ChartEdbInfoMapping, calculateValue int, calculateUnit string, percentType int) (edbList []*models.ChartEdbInfoMapping, dataResp response.LineFeatureDataResp, err error, errMsg string) {
  73. edbList = make([]*models.ChartEdbInfoMapping, 0)
  74. moveUnitDays, ok := utils.FrequencyDaysMap[calculateUnit]
  75. if !ok {
  76. errMsg = `错误的周期`
  77. err = errors.New(errMsg)
  78. return
  79. }
  80. calculateDay := calculateValue * moveUnitDays
  81. // 指标对应的所有数据
  82. _, edbList, err = data.GetEdbDataMapList(chartInfoId, 1, `公历`, startDate, endDate, []*models.ChartEdbInfoMapping{mappingInfo}, "")
  83. if err != nil {
  84. return
  85. }
  86. if len(edbList) != 1 {
  87. errMsg = `指标异常`
  88. err = errors.New(errMsg)
  89. return
  90. }
  91. edb := edbList[0]
  92. dataList := edb.DataList.([]*models.EdbDataList)
  93. newDataList := make([]models.EdbDataList, 0)
  94. var edbMinVal, edbMaxVal float64
  95. dataMap := make(map[time.Time]float64, 0)
  96. for _, tmpData := range dataList {
  97. currDateTime, _ := time.ParseInLocation(utils.FormatDate, tmpData.DataTime, time.Local)
  98. dataMap[currDateTime] = tmpData.Value
  99. }
  100. //百分位:对所选指标滚动地取对应时间长度的数据值,取最大值Max,最小值Min,计算Max-Min,百分位=(现值-Min)/(Max-Min),Max=Min时不予计算。
  101. if percentType == utils.PercentCalculateTypeRange {
  102. for i, tmpData := range dataList {
  103. currDateTime, _ := time.ParseInLocation(utils.FormatDate, tmpData.DataTime, time.Local)
  104. maxVal := tmpData.Value
  105. minVal := tmpData.Value
  106. for k := 0; k < calculateDay; k++ {
  107. preVal, ok2 := dataMap[currDateTime.AddDate(0, 0, -k)]
  108. if ok2 {
  109. if preVal > maxVal {
  110. maxVal = preVal
  111. }
  112. if preVal < minVal {
  113. minVal = preVal
  114. }
  115. }
  116. }
  117. if maxVal == minVal {
  118. continue
  119. }
  120. //百分位=(现值-Min)/(Max-Min)
  121. tmpV := (tmpData.Value - minVal) / (maxVal - minVal) * 100
  122. tmpV, _ = decimal.NewFromFloat(tmpV).Round(4).Float64()
  123. newDataList = append(newDataList, models.EdbDataList{
  124. EdbDataId: i,
  125. EdbInfoId: edb.EdbInfoId,
  126. DataTime: dataList[i].DataTime,
  127. DataTimestamp: dataList[i].DataTimestamp,
  128. Value: tmpV,
  129. })
  130. if tmpV < edbMinVal {
  131. edbMinVal = tmpV
  132. }
  133. if tmpV > edbMaxVal {
  134. edbMaxVal = tmpV
  135. }
  136. }
  137. }
  138. // 百分位数据个数算法
  139. // 数据区间第一个和最后一个数据点的时间和数据分别为(T1,S1)(T2,S2); N=T1到T2指标数据个数, n=小于等于S2的数据个数
  140. // 个数百分位=(n-1)/(N-1)
  141. if percentType == utils.PercentCalculateTypeNum {
  142. for i, d := range dataList {
  143. // T2为当前日期
  144. s2 := decimal.NewFromFloat(d.Value)
  145. t2, _ := time.ParseInLocation(utils.FormatDate, d.DataTime, time.Local)
  146. // 计算N和n
  147. var bigN, tinyN int
  148. for k := 0; k < calculateDay; k++ {
  149. preVal, preOk := dataMap[t2.AddDate(0, 0, -k)]
  150. if !preOk {
  151. continue
  152. }
  153. bigN += 1
  154. if decimal.NewFromFloat(preVal).LessThanOrEqual(s2) {
  155. tinyN += 1
  156. }
  157. }
  158. // N=1时说明计算无效
  159. if bigN == 1 {
  160. continue
  161. }
  162. numerator := decimal.NewFromInt(int64(tinyN - 1))
  163. denominator := decimal.NewFromInt(int64(bigN - 1))
  164. percentVal, _ := numerator.Div(denominator).Round(4).Float64()
  165. // 写进数组并判断指标最大最小值
  166. newDataList = append(newDataList, models.EdbDataList{
  167. EdbDataId: i,
  168. EdbInfoId: edb.EdbInfoId,
  169. DataTime: dataList[i].DataTime,
  170. DataTimestamp: dataList[i].DataTimestamp,
  171. Value: percentVal,
  172. })
  173. if percentVal < edbMinVal {
  174. edbMinVal = percentVal
  175. }
  176. if percentVal > edbMaxVal {
  177. edbMaxVal = percentVal
  178. }
  179. }
  180. }
  181. dataResp = response.LineFeatureDataResp{
  182. MaxData: edbMaxVal,
  183. MinData: edbMinVal,
  184. LatestDate: edb.LatestDate,
  185. EdbInfoCategoryType: edb.EdbInfoCategoryType,
  186. ChartColor: `#00F`,
  187. ChartStyle: `spline`,
  188. PredictChartColor: `#00F`,
  189. ChartType: 0,
  190. ChartWidth: 3,
  191. EdbName: "百分位",
  192. EdbNameEn: "percentile",
  193. Unit: "%",
  194. UnitEn: "%",
  195. IsAxis: 1,
  196. DataList: newDataList,
  197. }
  198. return
  199. }
  200. // GetFrequencyDistributionData 获取频率分布的图表数据
  201. func GetFrequencyDistributionData(chartInfoId int, mappingInfo *models.ChartEdbInfoMapping, dateType, stepVal int, startDate, endDate string) (edbList []*models.ChartEdbInfoMapping, dataResp response.FrequencyDistributionResp, err error, errMsg string) {
  202. XDataList := make([]float64, 0)
  203. // 频度
  204. Y1DataList := make([]response.FrequencyDistributionYData, 0)
  205. // 累计频率
  206. Y2DataList := make([]response.FrequencyDistributionYData, 0)
  207. edbList = make([]*models.ChartEdbInfoMapping, 0)
  208. // 指标对应的所有数据
  209. _, edbList, err = data.GetEdbDataMapList(chartInfoId, 1, `公历`, startDate, endDate, []*models.ChartEdbInfoMapping{mappingInfo}, "")
  210. if err != nil {
  211. return
  212. }
  213. if len(edbList) != 1 {
  214. err = errors.New("指标异常")
  215. return
  216. }
  217. startDateTime, _ := time.ParseInLocation(utils.FormatDate, startDate, time.Local)
  218. var endDateTime time.Time
  219. if endDate != `` {
  220. endDateTime, _ = time.ParseInLocation(utils.FormatDate, endDate, time.Local)
  221. }
  222. edb := edbList[0]
  223. dataList := edb.DataList.([]*models.EdbDataList)
  224. if len(dataList) <= 0 {
  225. return
  226. }
  227. // 非自定义
  228. if dateType != 8 {
  229. endDate = dataList[len(dataList)-1].DataTime
  230. endDateTime, err = time.ParseInLocation(utils.FormatDate, endDate, time.Local)
  231. if err != nil {
  232. return
  233. }
  234. //日期类型:1:最近3月;2:最近6月;3:最近1年;4:最近2年;5:最近3年;6:最近5年;7:最近10年,8:自定义时间
  235. startDateTime = utils.GetDateByDateType2(dateType, endDateTime)
  236. startDate = startDateTime.Format(utils.FormatDate)
  237. newDataList := make([]*models.EdbDataList, 0)
  238. for _, v := range dataList {
  239. tmpDataTime, tmpErr := time.ParseInLocation(utils.FormatDate, v.DataTime, time.Local)
  240. if tmpErr != nil {
  241. err = tmpErr
  242. return
  243. }
  244. if tmpDataTime.Equal(startDateTime) || tmpDataTime.After(startDateTime) {
  245. newDataList = append(newDataList, v)
  246. }
  247. }
  248. dataList = newDataList
  249. }
  250. maxVal := dataList[0].Value
  251. minVal := dataList[0].Value
  252. dataValMap := make(map[float64]int)
  253. total := 0 // 数据总量
  254. for _, tmpData := range dataList {
  255. currDateTime, _ := time.ParseInLocation(utils.FormatDate, tmpData.DataTime, time.Local)
  256. if (currDateTime.Equal(startDateTime) || currDateTime.After(startDateTime)) && (endDateTime.IsZero() || currDateTime.Before(endDateTime)) {
  257. if maxVal < tmpData.Value {
  258. maxVal = tmpData.Value
  259. }
  260. if minVal > tmpData.Value {
  261. minVal = tmpData.Value
  262. }
  263. num, ok := dataValMap[tmpData.Value]
  264. if ok {
  265. dataValMap[tmpData.Value] = num + 1
  266. } else {
  267. dataValMap[tmpData.Value] = 1
  268. }
  269. total++
  270. }
  271. }
  272. if total <= 0 {
  273. errMsg = `没有数据`
  274. err = errors.New(errMsg)
  275. return
  276. }
  277. // 最大最小值 向上/下取整
  278. minVal = utils.GetFloorNewNum(minVal, 2)
  279. maxVal = utils.GetCeilNewNum(maxVal, 2)
  280. //间距
  281. spacing, _ := (decimal.NewFromFloat(maxVal).Sub(decimal.NewFromFloat(minVal))).Div(decimal.NewFromInt(int64(stepVal))).Float64()
  282. distributionDataNumMap := make(map[float64]int)
  283. for i := 1; i <= stepVal; i++ {
  284. tmpMinVal, _ := decimal.NewFromFloat(minVal).Add((decimal.NewFromFloat(spacing)).Mul(decimal.NewFromInt(int64(i - 1)))).Float64()
  285. tmpMaxVal, _ := decimal.NewFromFloat(minVal).Add((decimal.NewFromFloat(spacing)).Mul(decimal.NewFromInt(int64(i)))).Float64()
  286. XDataList = append(XDataList, tmpMinVal)
  287. distributionDataNumMap[tmpMinVal] = 0
  288. for tmpVal, num := range dataValMap {
  289. if tmpMinVal <= tmpVal {
  290. // 最后一期数据是要小于等于
  291. if i == stepVal {
  292. if tmpVal <= tmpMaxVal {
  293. distributionDataNumMap[tmpMinVal] += num
  294. }
  295. } else {
  296. if tmpVal < tmpMaxVal {
  297. distributionDataNumMap[tmpMinVal] += num
  298. }
  299. }
  300. }
  301. }
  302. }
  303. var minFrequency, maxFrequency float64
  304. tmpNum := 0
  305. for k, tmpMinVal := range XDataList {
  306. // 数量
  307. frequencyYNum := distributionDataNumMap[tmpMinVal]
  308. // 频率
  309. tmpFrequency, _ := decimal.NewFromInt(int64(frequencyYNum)).Div(decimal.NewFromInt(int64(total))).Mul(decimal.NewFromInt(100)).Round(4).Float64()
  310. Y1DataList = append(Y1DataList, response.FrequencyDistributionYData{
  311. X: tmpMinVal,
  312. Y: tmpFrequency,
  313. })
  314. if k == 0 {
  315. minFrequency = tmpFrequency
  316. maxFrequency = tmpFrequency
  317. } else {
  318. if tmpFrequency < minFrequency {
  319. minFrequency = tmpFrequency
  320. }
  321. if tmpFrequency > maxFrequency {
  322. maxFrequency = tmpFrequency
  323. }
  324. }
  325. // 累计数
  326. tmpNum += frequencyYNum
  327. // 累计频率
  328. tmpTotalFrequency, _ := decimal.NewFromInt(int64(tmpNum)).Div(decimal.NewFromInt(int64(total))).Mul(decimal.NewFromInt(100)).Round(4).Float64()
  329. Y2DataList = append(Y2DataList, response.FrequencyDistributionYData{
  330. X: tmpMinVal,
  331. Y: tmpTotalFrequency,
  332. })
  333. }
  334. newDataList := []response.FrequencyDistributionData{
  335. {
  336. Name: "频率",
  337. NameEn: "Frequency",
  338. Unit: "%",
  339. UnitEn: "%",
  340. Value: Y1DataList,
  341. Color: "#00F",
  342. IsAxis: 1,
  343. }, {
  344. Name: "累计频率",
  345. NameEn: "Total Frequency",
  346. Unit: "%",
  347. UnitEn: "%",
  348. Value: Y2DataList,
  349. Color: "#F00",
  350. IsAxis: 0,
  351. },
  352. }
  353. edbList[0].DataList = nil
  354. dataResp = response.FrequencyDistributionResp{
  355. LeftMinValue: minFrequency,
  356. LeftMaxValue: maxFrequency,
  357. RightMinValue: 0,
  358. RightMaxValue: 100,
  359. DataList: newDataList,
  360. }
  361. return
  362. }