chart_info.go 12 KB

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