Plot.go 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467
  1. package giu
  2. import (
  3. "image"
  4. "github.com/AllenDang/imgui-go"
  5. )
  6. // PlotWidget is implemented by all the particular plots, which can be used
  7. // in (*PlotCanvasWidget).Plots.
  8. type PlotWidget interface {
  9. Plot()
  10. }
  11. // ImPlotYAxis represents y axis settings.
  12. type ImPlotYAxis int
  13. // ImPlotYAxis enum:.
  14. const (
  15. ImPlotYAxisLeft ImPlotYAxis = 0 // left (default)
  16. ImPlotYAxisFirstOnRight ImPlotYAxis = 1 // first on right side
  17. ImPlotYAxisSecondOnRight ImPlotYAxis = 2 // second on right side
  18. )
  19. // PlotTicker represents axis ticks.
  20. type PlotTicker struct {
  21. Position float64
  22. Label string
  23. }
  24. // PlotCanvasWidget represents a giu plot widget.
  25. type PlotCanvasWidget struct {
  26. title string
  27. xLabel string
  28. yLabel string
  29. width int
  30. height int
  31. flags PlotFlags
  32. xFlags, yFlags, y2Flags, y3Flags PlotAxisFlags
  33. y2Label string
  34. y3Label string
  35. xMin, xMax, yMin, yMax float64
  36. axisLimitCondition ExecCondition
  37. xTicksValue, yTicksValue []float64
  38. xTicksLabel, yTicksLabel []string
  39. xTicksShowDefault bool
  40. yTicksShowDefault bool
  41. yTicksYAxis ImPlotYAxis
  42. plots []PlotWidget
  43. }
  44. // Plot adds creates a new plot widget.
  45. func Plot(title string) *PlotCanvasWidget {
  46. return &PlotCanvasWidget{
  47. title: title,
  48. xLabel: "",
  49. yLabel: "",
  50. width: -1,
  51. height: 0,
  52. flags: PlotFlagsNone,
  53. xFlags: PlotAxisFlagsNone,
  54. yFlags: PlotAxisFlagsNone,
  55. y2Flags: PlotAxisFlagsNoGridLines,
  56. y3Flags: PlotAxisFlagsNoGridLines,
  57. y2Label: "",
  58. y3Label: "",
  59. xMin: 0,
  60. xMax: 10,
  61. yMin: 0,
  62. yMax: 10,
  63. xTicksShowDefault: true,
  64. yTicksShowDefault: true,
  65. yTicksYAxis: 0,
  66. axisLimitCondition: ConditionOnce,
  67. }
  68. }
  69. // AxisLimits sets X and Y axis limits.
  70. func (p *PlotCanvasWidget) AxisLimits(xmin, xmax, ymin, ymax float64, cond ExecCondition) *PlotCanvasWidget {
  71. p.xMin = xmin
  72. p.xMax = xmax
  73. p.yMin = ymin
  74. p.yMax = ymax
  75. p.axisLimitCondition = cond
  76. return p
  77. }
  78. // XTicks sets x axis ticks.
  79. func (p *PlotCanvasWidget) XTicks(ticks []PlotTicker, showDefault bool) *PlotCanvasWidget {
  80. length := len(ticks)
  81. if length == 0 {
  82. return p
  83. }
  84. values := make([]float64, length)
  85. labels := make([]string, length)
  86. for i, t := range ticks {
  87. values[i] = t.Position
  88. labels[i] = t.Label
  89. }
  90. p.xTicksValue = values
  91. p.xTicksLabel = labels
  92. p.xTicksShowDefault = showDefault
  93. return p
  94. }
  95. // YTicks sets y axis ticks.
  96. func (p *PlotCanvasWidget) YTicks(ticks []PlotTicker, showDefault bool, yAxis ImPlotYAxis) *PlotCanvasWidget {
  97. length := len(ticks)
  98. if length == 0 {
  99. return p
  100. }
  101. values := make([]float64, length)
  102. labels := make([]string, length)
  103. for i, t := range ticks {
  104. values[i] = t.Position
  105. labels[i] = t.Label
  106. }
  107. p.yTicksValue = values
  108. p.yTicksLabel = labels
  109. p.yTicksShowDefault = showDefault
  110. p.yTicksYAxis = yAxis
  111. return p
  112. }
  113. // Flags sets plot canvas flags.
  114. func (p *PlotCanvasWidget) Flags(flags PlotFlags) *PlotCanvasWidget {
  115. p.flags = flags
  116. return p
  117. }
  118. // XAxeFlags sets x axis fags.
  119. func (p *PlotCanvasWidget) XAxeFlags(flags PlotAxisFlags) *PlotCanvasWidget {
  120. p.xFlags = flags
  121. return p
  122. }
  123. // YAxeFlags sets y axis flags.
  124. func (p *PlotCanvasWidget) YAxeFlags(yFlags, y2Flags, y3Flags PlotAxisFlags) *PlotCanvasWidget {
  125. p.yFlags = yFlags
  126. p.y2Flags = y2Flags
  127. p.y3Flags = y3Flags
  128. return p
  129. }
  130. // Plots adds plots to plot canvas.
  131. func (p *PlotCanvasWidget) Plots(plots ...PlotWidget) *PlotCanvasWidget {
  132. p.plots = plots
  133. return p
  134. }
  135. // Size set canvas size.
  136. func (p *PlotCanvasWidget) Size(width, height int) *PlotCanvasWidget {
  137. p.width = width
  138. p.height = height
  139. return p
  140. }
  141. // Build implements Widget interface.
  142. func (p *PlotCanvasWidget) Build() {
  143. if len(p.plots) > 0 {
  144. imgui.ImPlotSetNextPlotLimits(p.xMin, p.xMax, p.yMin, p.yMax, imgui.Condition(p.axisLimitCondition))
  145. if len(p.xTicksValue) > 0 {
  146. imgui.ImPlotSetNextPlotTicksX(p.xTicksValue, p.xTicksLabel, p.xTicksShowDefault)
  147. }
  148. if len(p.yTicksValue) > 0 {
  149. imgui.ImPlotSetNextPlotTicksY(p.yTicksValue, p.yTicksLabel, p.yTicksShowDefault, int(p.yTicksYAxis))
  150. }
  151. if imgui.ImPlotBegin(
  152. tStr(p.title), tStr(p.xLabel),
  153. tStr(p.yLabel), ToVec2(image.Pt(p.width, p.height)),
  154. imgui.ImPlotFlags(p.flags), imgui.ImPlotAxisFlags(p.xFlags),
  155. imgui.ImPlotAxisFlags(p.yFlags), imgui.ImPlotAxisFlags(p.y2Flags),
  156. imgui.ImPlotAxisFlags(p.y3Flags), tStr(p.y2Label), tStr(p.y3Label),
  157. ) {
  158. for _, plot := range p.plots {
  159. plot.Plot()
  160. }
  161. imgui.ImPlotEnd()
  162. }
  163. }
  164. }
  165. // PlotBarWidget adds bar plot (column chart) to the canvas.
  166. type PlotBarWidget struct {
  167. title string
  168. data []float64
  169. width float64
  170. shift float64
  171. offset int
  172. }
  173. // PlotBar adds a plot bar (column chart).
  174. func PlotBar(title string, data []float64) *PlotBarWidget {
  175. return &PlotBarWidget{
  176. title: title,
  177. data: data,
  178. width: 0.2,
  179. shift: 0,
  180. offset: 0,
  181. }
  182. }
  183. // Width sets bar width.
  184. func (p *PlotBarWidget) Width(width float64) *PlotBarWidget {
  185. p.width = width
  186. return p
  187. }
  188. // Shift sets shift of the bar.
  189. func (p *PlotBarWidget) Shift(shift float64) *PlotBarWidget {
  190. p.shift = shift
  191. return p
  192. }
  193. // Offset sets bar's offset.
  194. func (p *PlotBarWidget) Offset(offset int) *PlotBarWidget {
  195. p.offset = offset
  196. return p
  197. }
  198. // Plot implements Plot interface.
  199. func (p *PlotBarWidget) Plot() {
  200. imgui.ImPlotBars(p.title, p.data, p.width, p.shift, p.offset)
  201. }
  202. // PlotBarHWidget represents a column chart on Y axis.
  203. type PlotBarHWidget struct {
  204. title string
  205. data []float64
  206. height float64
  207. shift float64
  208. offset int
  209. }
  210. // PlotBarH adds plot bars on y axis.
  211. func PlotBarH(title string, data []float64) *PlotBarHWidget {
  212. return &PlotBarHWidget{
  213. title: title,
  214. data: data,
  215. height: 0.2,
  216. shift: 0,
  217. offset: 0,
  218. }
  219. }
  220. // Height sets bar height (in fact bars' width).
  221. func (p *PlotBarHWidget) Height(height float64) *PlotBarHWidget {
  222. p.height = height
  223. return p
  224. }
  225. // Shift sets shift.
  226. func (p *PlotBarHWidget) Shift(shift float64) *PlotBarHWidget {
  227. p.shift = shift
  228. return p
  229. }
  230. // Offset sets offset.
  231. func (p *PlotBarHWidget) Offset(offset int) *PlotBarHWidget {
  232. p.offset = offset
  233. return p
  234. }
  235. // Plot implements plot interface.
  236. func (p *PlotBarHWidget) Plot() {
  237. imgui.ImPlotBarsH(tStr(p.title), p.data, p.height, p.shift, p.offset)
  238. }
  239. // PlotLineWidget represents a plot line (linear chart).
  240. type PlotLineWidget struct {
  241. title string
  242. values []float64
  243. xScale, x0 float64
  244. offset int
  245. yAxis ImPlotYAxis
  246. }
  247. // PlotLine adds a new plot line to the canvas.
  248. func PlotLine(title string, values []float64) *PlotLineWidget {
  249. return &PlotLineWidget{
  250. title: title,
  251. values: values,
  252. xScale: 1,
  253. x0: 0,
  254. offset: 0,
  255. }
  256. }
  257. // SetPlotYAxis sets yAxis parameters.
  258. func (p *PlotLineWidget) SetPlotYAxis(yAxis ImPlotYAxis) *PlotLineWidget {
  259. p.yAxis = yAxis
  260. return p
  261. }
  262. // XScale sets x-axis-scale.
  263. func (p *PlotLineWidget) XScale(scale float64) *PlotLineWidget {
  264. p.xScale = scale
  265. return p
  266. }
  267. // X0 sets a start position on x axis.
  268. func (p *PlotLineWidget) X0(x0 float64) *PlotLineWidget {
  269. p.x0 = x0
  270. return p
  271. }
  272. // Offset sets chart offset.
  273. func (p *PlotLineWidget) Offset(offset int) *PlotLineWidget {
  274. p.offset = offset
  275. return p
  276. }
  277. // Plot implements Plot interface.
  278. func (p *PlotLineWidget) Plot() {
  279. imgui.ImPlotSetPlotYAxis(imgui.ImPlotYAxis(p.yAxis))
  280. imgui.ImPlotLine(tStr(p.title), p.values, p.xScale, p.x0, p.offset)
  281. }
  282. // PlotLineXYWidget adds XY plot line.
  283. type PlotLineXYWidget struct {
  284. title string
  285. xs, ys []float64
  286. offset int
  287. yAxis ImPlotYAxis
  288. }
  289. // PlotLineXY adds XY plot line to canvas.
  290. func PlotLineXY(title string, xvalues, yvalues []float64) *PlotLineXYWidget {
  291. return &PlotLineXYWidget{
  292. title: title,
  293. xs: xvalues,
  294. ys: yvalues,
  295. offset: 0,
  296. }
  297. }
  298. // SetPlotYAxis sets yAxis parameters.
  299. func (p *PlotLineXYWidget) SetPlotYAxis(yAxis ImPlotYAxis) *PlotLineXYWidget {
  300. p.yAxis = yAxis
  301. return p
  302. }
  303. // Offset sets chart's offset.
  304. func (p *PlotLineXYWidget) Offset(offset int) *PlotLineXYWidget {
  305. p.offset = offset
  306. return p
  307. }
  308. // Plot implements Plot interface.
  309. func (p *PlotLineXYWidget) Plot() {
  310. imgui.ImPlotSetPlotYAxis(imgui.ImPlotYAxis(p.yAxis))
  311. imgui.ImPlotLineXY(tStr(p.title), p.xs, p.ys, p.offset)
  312. }
  313. // PlotPieChartWidget represents a pie chart.
  314. type PlotPieChartWidget struct {
  315. labels []string
  316. values []float64
  317. x, y, radius float64
  318. normalize bool
  319. labelFormat string
  320. angle0 float64
  321. }
  322. // PlotPieChart adds pie chart to the canvas.
  323. func PlotPieChart(labels []string, values []float64, x, y, radius float64) *PlotPieChartWidget {
  324. return &PlotPieChartWidget{
  325. labels: labels,
  326. values: values,
  327. x: x,
  328. y: y,
  329. radius: radius,
  330. normalize: false,
  331. labelFormat: "%.1f",
  332. angle0: 90,
  333. }
  334. }
  335. func (p *PlotPieChartWidget) Normalize(n bool) *PlotPieChartWidget {
  336. p.normalize = n
  337. return p
  338. }
  339. // LabelFormat sets format of labels.
  340. func (p *PlotPieChartWidget) LabelFormat(fmtStr string) *PlotPieChartWidget {
  341. p.labelFormat = fmtStr
  342. return p
  343. }
  344. func (p *PlotPieChartWidget) Angle0(a float64) *PlotPieChartWidget {
  345. p.angle0 = a
  346. return p
  347. }
  348. func (p *PlotPieChartWidget) Plot() {
  349. imgui.ImPlotPieChart(tStrSlice(p.labels), p.values, p.x, p.y, p.radius, p.normalize, p.labelFormat, p.angle0)
  350. }
  351. type PlotScatterWidget struct {
  352. label string
  353. values []float64
  354. xscale, x0 float64
  355. offset int
  356. }
  357. func PlotScatter(label string, values []float64) *PlotScatterWidget {
  358. return &PlotScatterWidget{
  359. label: label,
  360. values: values,
  361. xscale: 1,
  362. x0: 0,
  363. offset: 0,
  364. }
  365. }
  366. func (p *PlotScatterWidget) XScale(s float64) *PlotScatterWidget {
  367. p.xscale = s
  368. return p
  369. }
  370. func (p *PlotScatterWidget) X0(x float64) *PlotScatterWidget {
  371. p.x0 = x
  372. return p
  373. }
  374. func (p *PlotScatterWidget) Offset(offset int) *PlotScatterWidget {
  375. p.offset = offset
  376. return p
  377. }
  378. func (p *PlotScatterWidget) Plot() {
  379. imgui.ImPlotScatter(tStr(p.label), p.values, p.xscale, p.x0, p.offset)
  380. }
  381. type PlotScatterXYWidget struct {
  382. label string
  383. xs, ys []float64
  384. offset int
  385. }
  386. func PlotScatterXY(label string, xs, ys []float64) *PlotScatterXYWidget {
  387. return &PlotScatterXYWidget{
  388. label: label,
  389. xs: xs,
  390. ys: ys,
  391. offset: 0,
  392. }
  393. }
  394. func (p *PlotScatterXYWidget) Offset(offset int) *PlotScatterXYWidget {
  395. p.offset = offset
  396. return p
  397. }
  398. func (p *PlotScatterXYWidget) Plot() {
  399. imgui.ImPlotScatterXY(tStr(p.label), p.xs, p.ys, p.offset)
  400. }