Graphs.swift 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389
  1. //
  2. // Graphs.swift
  3. // LoopFollow
  4. //
  5. // Created by Jon Fawcett on 6/16/20.
  6. // Copyright © 2020 Jon Fawcett. All rights reserved.
  7. //
  8. import Foundation
  9. import Charts
  10. import UIKit
  11. extension MainViewController {
  12. func chartValueSelected(_ chartView: ChartViewBase, entry: ChartDataEntry, highlight: Highlight) {
  13. if chartView == BGChartFull {
  14. BGChart.moveViewToX(entry.x)
  15. }
  16. }
  17. func chartTranslated(_ chartView: ChartViewBase, dX: CGFloat, dY: CGFloat) {
  18. if chartView == BGChart {
  19. let currentMatrix = chartView.viewPortHandler.touchMatrix
  20. //BGChartFull.viewPortHandler.refresh(newMatrix: currentMatrix, chart: BGChartFull, invalidate: true)
  21. //BGChartFull.highlightValue(x: Double(currentMatrix.tx), y: Double(currentMatrix.ty), dataSetIndex: 0)
  22. }
  23. }
  24. // data.addDataSet(lineBG) // Dataset 0
  25. // data.addDataSet(lineBasal) // Dataset 1
  26. // data.addDataSet(lineBolus) // Dataset 2
  27. // data.addDataSet(lineCarbs) // Dataset 3
  28. func createGraph(){
  29. self.BGChart.clear()
  30. // Create the BG Graph Data
  31. let entries = bgData
  32. var bgChartEntry = [ChartDataEntry]()
  33. var colors = [NSUIColor]()
  34. var maxBG: Float = UserDefaultsRepository.minBGScale.value
  35. // Setup BG line details
  36. let lineBG = LineChartDataSet(entries:bgChartEntry, label: "")
  37. lineBG.circleRadius = 3
  38. lineBG.circleColors = [NSUIColor.systemGreen]
  39. lineBG.drawCircleHoleEnabled = false
  40. lineBG.axisDependency = YAxis.AxisDependency.right
  41. lineBG.highlightEnabled = false
  42. lineBG.drawValuesEnabled = false
  43. if UserDefaultsRepository.showLines.value {
  44. lineBG.lineWidth = 2
  45. } else {
  46. lineBG.lineWidth = 0
  47. }
  48. if UserDefaultsRepository.showDots.value {
  49. lineBG.drawCirclesEnabled = true
  50. } else {
  51. lineBG.drawCirclesEnabled = false
  52. }
  53. lineBG.setDrawHighlightIndicators(false)
  54. lineBG.valueFont.withSize(50)
  55. // create Basal graph data
  56. var chartEntry = [ChartDataEntry]()
  57. var maxBasal = UserDefaultsRepository.minBasalScale.value
  58. let lineBasal = LineChartDataSet(entries:chartEntry, label: "")
  59. lineBasal.setDrawHighlightIndicators(false)
  60. lineBasal.setColor(NSUIColor.systemBlue, alpha: 0.5)
  61. lineBasal.lineWidth = 0
  62. lineBasal.drawFilledEnabled = true
  63. lineBasal.fillColor = NSUIColor.systemBlue.withAlphaComponent(0.8)
  64. lineBasal.drawCirclesEnabled = false
  65. lineBasal.axisDependency = YAxis.AxisDependency.left
  66. lineBasal.highlightEnabled = false
  67. lineBasal.drawValuesEnabled = false
  68. // Boluses
  69. var chartEntryBolus = [ChartDataEntry]()
  70. let lineBolus = LineChartDataSet(entries:chartEntryBolus, label: "")
  71. lineBolus.circleRadius = 7
  72. lineBolus.circleColors = [NSUIColor.systemBlue.withAlphaComponent(0.75)]
  73. lineBolus.drawCircleHoleEnabled = false
  74. lineBolus.setDrawHighlightIndicators(false)
  75. lineBolus.setColor(NSUIColor.systemBlue, alpha: 1.0)
  76. lineBolus.drawCirclesEnabled = true
  77. lineBolus.lineWidth = 0
  78. lineBolus.axisDependency = YAxis.AxisDependency.right
  79. lineBolus.valueFormatter = ChartYDataValueFormatter()
  80. lineBolus.drawValuesEnabled = true
  81. lineBolus.valueTextColor = NSUIColor.label
  82. // Carbs
  83. var chartEntryCarbs = [ChartDataEntry]()
  84. let lineCarbs = LineChartDataSet(entries:chartEntryCarbs, label: "")
  85. lineCarbs.circleRadius = 7
  86. lineCarbs.circleColors = [NSUIColor.systemOrange.withAlphaComponent(0.75)]
  87. lineCarbs.drawCircleHoleEnabled = false
  88. lineCarbs.setDrawHighlightIndicators(false)
  89. lineCarbs.setColor(NSUIColor.systemBlue, alpha: 1.0)
  90. lineCarbs.drawCirclesEnabled = true
  91. lineCarbs.lineWidth = 0
  92. lineCarbs.axisDependency = YAxis.AxisDependency.right
  93. lineCarbs.valueFormatter = ChartYDataValueFormatter()
  94. lineCarbs.drawValuesEnabled = true
  95. lineCarbs.valueTextColor = NSUIColor.label
  96. // Setup the chart data of all lines
  97. let data = LineChartData()
  98. data.addDataSet(lineBG) // Dataset 0
  99. data.addDataSet(lineBasal) // Dataset 1
  100. data.addDataSet(lineBolus) // Dataset 2
  101. data.addDataSet(lineCarbs) // Dataset 3
  102. data.setValueFont(UIFont.systemFont(ofSize: 12))
  103. // Clear limit lines so they don't add multiples when changing the settings
  104. BGChart.rightAxis.removeAllLimitLines()
  105. //Add lower red line based on low alert value
  106. let ll = ChartLimitLine()
  107. ll.limit = Double(UserDefaultsRepository.lowLine.value)
  108. ll.lineColor = NSUIColor.systemRed.withAlphaComponent(0.5)
  109. BGChart.rightAxis.addLimitLine(ll)
  110. //Add upper yellow line based on low alert value
  111. let ul = ChartLimitLine()
  112. ul.limit = Double(UserDefaultsRepository.highLine.value)
  113. ul.lineColor = NSUIColor.systemYellow.withAlphaComponent(0.5)
  114. BGChart.rightAxis.addLimitLine(ul)
  115. // Setup the main graph overall details
  116. BGChart.xAxis.valueFormatter = ChartXValueFormatter()
  117. BGChart.xAxis.granularity = 1800
  118. BGChart.xAxis.labelTextColor = NSUIColor.label
  119. BGChart.xAxis.labelPosition = XAxis.LabelPosition.bottom
  120. BGChart.xAxis.drawGridLinesEnabled = false
  121. BGChart.leftAxis.enabled = true
  122. BGChart.leftAxis.labelPosition = YAxis.LabelPosition.insideChart
  123. BGChart.leftAxis.axisMaximum = maxBasal
  124. BGChart.leftAxis.axisMinimum = 0.0
  125. BGChart.leftAxis.drawGridLinesEnabled = false
  126. BGChart.rightAxis.labelTextColor = NSUIColor.label
  127. BGChart.rightAxis.labelPosition = YAxis.LabelPosition.insideChart
  128. BGChart.rightAxis.axisMinimum = 40
  129. BGChart.rightAxis.axisMaximum = Double(maxBG)
  130. BGChart.rightAxis.gridLineDashLengths = [5.0, 5.0]
  131. BGChart.rightAxis.valueFormatter = ChartYMMOLValueFormatter()
  132. BGChart.legend.enabled = false
  133. BGChart.scaleYEnabled = false
  134. BGChart.drawGridBackgroundEnabled = false
  135. //BGChart.gridBackgroundColor = NSUIColor.secondarySystemBackground
  136. BGChart.data = data
  137. BGChart.setExtraOffsets(left: 10, top: 10, right: 10, bottom: 10)
  138. BGChart.setVisibleXRangeMinimum(10)
  139. }
  140. func updateBGGraphSettings() {
  141. let dataIndex = 0
  142. let lineBG = BGChart.lineData!.dataSets[dataIndex] as! LineChartDataSet
  143. if UserDefaultsRepository.showLines.value {
  144. lineBG.lineWidth = 2
  145. } else {
  146. lineBG.lineWidth = 0
  147. }
  148. if UserDefaultsRepository.showDots.value {
  149. lineBG.drawCirclesEnabled = true
  150. } else {
  151. lineBG.drawCirclesEnabled = false
  152. }
  153. // Clear limit lines so they don't add multiples when changing the settings
  154. BGChart.rightAxis.removeAllLimitLines()
  155. //Add lower red line based on low alert value
  156. let ll = ChartLimitLine()
  157. ll.limit = Double(UserDefaultsRepository.lowLine.value)
  158. ll.lineColor = NSUIColor.systemRed.withAlphaComponent(0.5)
  159. BGChart.rightAxis.addLimitLine(ll)
  160. //Add upper yellow line based on low alert value
  161. let ul = ChartLimitLine()
  162. ul.limit = Double(UserDefaultsRepository.highLine.value)
  163. ul.lineColor = NSUIColor.systemYellow.withAlphaComponent(0.5)
  164. BGChart.rightAxis.addLimitLine(ul)
  165. BGChart.data?.dataSets[dataIndex].notifyDataSetChanged()
  166. BGChart.data?.notifyDataChanged()
  167. BGChart.notifyDataSetChanged()
  168. }
  169. func updateBGGraph() {
  170. let dataIndex = 0
  171. let entries = bgData
  172. var mainChart = BGChart.lineData!.dataSets[dataIndex] as! LineChartDataSet
  173. var smallChart = BGChartFull.lineData!.dataSets[dataIndex] as! LineChartDataSet
  174. mainChart.clear()
  175. smallChart.clear()
  176. var maxBG = UserDefaultsRepository.minBGScale.value
  177. var maxBGOffset: Float = 0.0
  178. if UserDefaultsRepository.offsetCarbsBolus.value {
  179. maxBGOffset = 40.0
  180. }
  181. var colors = [NSUIColor]()
  182. for i in 0..<entries.count{
  183. if Float(entries[i].sgv) > maxBG - maxBGOffset {
  184. maxBG = Float(entries[i].sgv) + maxBGOffset
  185. }
  186. let value = ChartDataEntry(x: Double(entries[i].date), y: Double(entries[i].sgv))
  187. mainChart.addEntry(value)
  188. smallChart.addEntry(value)
  189. if Double(entries[i].sgv) >= Double(UserDefaultsRepository.highLine.value) {
  190. colors.append(NSUIColor.systemYellow)
  191. } else if Double(entries[i].sgv) <= Double(UserDefaultsRepository.lowLine.value) {
  192. colors.append(NSUIColor.systemRed)
  193. } else {
  194. colors.append(NSUIColor.systemGreen)
  195. }
  196. }
  197. // Add Prediction Data
  198. if predictionData.count > 0 && bgData.count > 0 && UserDefaultsRepository.graphPrediction.value {
  199. print("graph prediction")
  200. var startingTime = entries[entries.count - 1].date + 300
  201. var i = 0
  202. // Add 1 hour of predictions
  203. while i < 12 {
  204. var predictionVal = Double(predictionData[i])
  205. // Below can be turned on to prevent out of range on the graph if desired.
  206. // It currently just drops them out of view
  207. if predictionVal > 400 {
  208. // predictionVal = 400
  209. } else if predictionVal < 0 {
  210. // predictionVal = 0
  211. }
  212. let value = ChartDataEntry(x: startingTime + 5, y: predictionVal)
  213. mainChart.addEntry(value)
  214. smallChart.addEntry(value)
  215. colors.append(NSUIColor.systemPurple)
  216. startingTime += 300
  217. i += 1
  218. }
  219. }
  220. // Set Colors
  221. let lineBG = BGChart.lineData!.dataSets[dataIndex] as! LineChartDataSet
  222. let lineBGSmall = BGChartFull.lineData!.dataSets[dataIndex] as! LineChartDataSet
  223. lineBG.colors.removeAll()
  224. lineBG.circleColors.removeAll()
  225. lineBGSmall.colors.removeAll()
  226. lineBGSmall.circleColors.removeAll()
  227. if colors.count > 0 {
  228. print("graph colors")
  229. for i in 0..<colors.count{
  230. mainChart.addColor(colors[i])
  231. mainChart.circleColors.append(colors[i])
  232. smallChart.addColor(colors[i])
  233. smallChart.circleColors.append(colors[i])
  234. }
  235. }
  236. BGChart.rightAxis.axisMaximum = Double(maxBG)
  237. BGChart.data?.dataSets[dataIndex].notifyDataSetChanged()
  238. BGChart.data?.notifyDataChanged()
  239. BGChart.notifyDataSetChanged()
  240. BGChartFull.data?.dataSets[dataIndex].notifyDataSetChanged()
  241. BGChartFull.data?.notifyDataChanged()
  242. BGChartFull.notifyDataSetChanged()
  243. if firstGraphLoad {
  244. BGChart.zoom(scaleX: 18, scaleY: 1, x: 1, y: 1)
  245. firstGraphLoad = false
  246. }
  247. if BGChart.chartXMax > dateTimeUtils.getNowTimeIntervalUTC() {
  248. BGChart.moveViewToAnimated(xValue: dateTimeUtils.getNowTimeIntervalUTC() - (BGChart.visibleXRange * 0.7), yValue: 0.0, axis: .right, duration: 1, easingOption: .easeInBack)
  249. }
  250. }
  251. func updateBasalGraph() {
  252. var dataIndex = 1
  253. BGChart.lineData?.dataSets[dataIndex].clear()
  254. var maxBasal = UserDefaultsRepository.minBasalScale.value
  255. for i in 0..<basalData.count{
  256. let value = ChartDataEntry(x: Double(basalData[i].date), y: Double(basalData[i].basalRate))
  257. BGChart.data?.dataSets[dataIndex].addEntry(value)
  258. if basalData[i].basalRate > maxBasal {
  259. maxBasal = basalData[i].basalRate
  260. }
  261. }
  262. BGChart.leftAxis.axisMaximum = maxBasal
  263. BGChart.data?.dataSets[dataIndex].notifyDataSetChanged()
  264. BGChart.data?.notifyDataChanged()
  265. BGChart.notifyDataSetChanged()
  266. }
  267. func updateBolusGraph() {
  268. var dataIndex = 2
  269. BGChart.lineData?.dataSets[dataIndex].clear()
  270. for i in 0..<bolusData.count{
  271. let formatter = NumberFormatter()
  272. formatter.minimumFractionDigits = 0
  273. formatter.maximumFractionDigits = 2
  274. formatter.minimumIntegerDigits = 1
  275. var offset = 0
  276. if UserDefaultsRepository.offsetCarbsBolus.value {
  277. offset = 10
  278. }
  279. let value = ChartDataEntry(x: Double(bolusData[i].date), y: Double(bolusData[i].sgv + offset), data: formatter.string(from: NSNumber(value: bolusData[i].value)))
  280. BGChart.data?.dataSets[dataIndex].addEntry(value)
  281. }
  282. BGChart.data?.dataSets[dataIndex].notifyDataSetChanged()
  283. BGChart.data?.notifyDataChanged()
  284. BGChart.notifyDataSetChanged()
  285. }
  286. func updateCarbGraph() {
  287. var dataIndex = 3
  288. BGChart.lineData?.dataSets[dataIndex].clear()
  289. for i in 0..<carbData.count{
  290. let formatter = NumberFormatter()
  291. formatter.minimumFractionDigits = 0
  292. formatter.maximumFractionDigits = 2
  293. formatter.minimumIntegerDigits = 1
  294. var offset = 0
  295. if UserDefaultsRepository.offsetCarbsBolus.value {
  296. offset = 30
  297. }
  298. let value = ChartDataEntry(x: Double(carbData[i].date), y: Double(carbData[i].sgv + offset), data: formatter.string(from: NSNumber(value: carbData[i].value)))
  299. BGChart.data?.dataSets[dataIndex].addEntry(value)
  300. }
  301. BGChart.data?.dataSets[dataIndex].notifyDataSetChanged()
  302. BGChart.data?.notifyDataChanged()
  303. BGChart.notifyDataSetChanged()
  304. }
  305. func createSmallBGGraph(){
  306. let entries = bgData
  307. var bgChartEntry = [ChartDataEntry]()
  308. var colors = [NSUIColor]()
  309. let lineBG = LineChartDataSet(entries:bgChartEntry, label: "")
  310. lineBG.drawCirclesEnabled = false
  311. //line2.setDrawHighlightIndicators(false)
  312. lineBG.highlightEnabled = true
  313. lineBG.drawHorizontalHighlightIndicatorEnabled = false
  314. lineBG.drawVerticalHighlightIndicatorEnabled = false
  315. lineBG.highlightColor = NSUIColor.label
  316. lineBG.drawValuesEnabled = false
  317. lineBG.lineWidth = 2
  318. let data2 = LineChartData()
  319. data2.addDataSet(lineBG)
  320. BGChartFull.highlightPerDragEnabled = true
  321. BGChartFull.leftAxis.enabled = false
  322. BGChartFull.rightAxis.enabled = false
  323. BGChartFull.xAxis.enabled = false
  324. BGChartFull.legend.enabled = false
  325. BGChartFull.scaleYEnabled = false
  326. BGChartFull.scaleXEnabled = false
  327. BGChartFull.drawGridBackgroundEnabled = false
  328. BGChartFull.data = data2
  329. }
  330. }