GraphViewExample.cs 37 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036
  1. using System;
  2. using System.Collections.Generic;
  3. using System.ComponentModel;
  4. using System.Linq;
  5. using System.Text;
  6. using Terminal.Gui;
  7. using Application = Terminal.Gui.Application;
  8. namespace UICatalog.Scenarios;
  9. [ScenarioMetadata ("Graph View", "Demos the GraphView control.")]
  10. [ScenarioCategory ("Controls")]
  11. [ScenarioCategory ("Drawing")]
  12. public class GraphViewExample : Scenario
  13. {
  14. private readonly Thickness _thickness = new (1, 1, 1, 1);
  15. private TextView _about;
  16. private int _currentGraph;
  17. private Action [] _graphs;
  18. private GraphView _graphView;
  19. private MenuItem _miDiags;
  20. private MenuItem _miShowBorder;
  21. private ViewDiagnosticFlags _viewDiagnostics;
  22. public override void Main ()
  23. {
  24. Application.Init ();
  25. Toplevel app = new ();
  26. _graphs = new []
  27. {
  28. () => SetupPeriodicTableScatterPlot (), //0
  29. () => SetupLifeExpectancyBarGraph (true), //1
  30. () => SetupLifeExpectancyBarGraph (false), //2
  31. () => SetupPopulationPyramid (), //3
  32. () => SetupLineGraph (), //4
  33. () => SetupSineWave (), //5
  34. () => SetupDisco (), //6
  35. () => MultiBarGraph () //7
  36. };
  37. var menu = new MenuBar
  38. {
  39. Menus =
  40. [
  41. new (
  42. "_File",
  43. new MenuItem []
  44. {
  45. new (
  46. "Scatter _Plot",
  47. "",
  48. () => _graphs [_currentGraph =
  49. 0] ()
  50. ),
  51. new (
  52. "_V Bar Graph",
  53. "",
  54. () => _graphs [_currentGraph =
  55. 1] ()
  56. ),
  57. new (
  58. "_H Bar Graph",
  59. "",
  60. () => _graphs [_currentGraph =
  61. 2] ()
  62. ),
  63. new (
  64. "P_opulation Pyramid",
  65. "",
  66. () => _graphs [_currentGraph =
  67. 3] ()
  68. ),
  69. new (
  70. "_Line Graph",
  71. "",
  72. () => _graphs [_currentGraph =
  73. 4] ()
  74. ),
  75. new (
  76. "Sine _Wave",
  77. "",
  78. () => _graphs [_currentGraph =
  79. 5] ()
  80. ),
  81. new (
  82. "Silent _Disco",
  83. "",
  84. () => _graphs [_currentGraph =
  85. 6] ()
  86. ),
  87. new (
  88. "_Multi Bar Graph",
  89. "",
  90. () => _graphs [_currentGraph =
  91. 7] ()
  92. ),
  93. new ("_Quit", "", () => Quit ())
  94. }
  95. ),
  96. new (
  97. "_View",
  98. new []
  99. {
  100. new ("Zoom _In", "", () => Zoom (0.5f)),
  101. new ("Zoom _Out", "", () => Zoom (2f)),
  102. new ("MarginLeft++", "", () => Margin (true, true)),
  103. new ("MarginLeft--", "", () => Margin (true, false)),
  104. new ("MarginBottom++", "", () => Margin (false, true)),
  105. new ("MarginBottom--", "", () => Margin (false, false)),
  106. _miShowBorder = new (
  107. "_Enable Margin, Border, and Padding",
  108. "",
  109. () => ShowBorder ()
  110. )
  111. {
  112. Checked = true,
  113. CheckType = MenuItemCheckStyle
  114. .Checked
  115. },
  116. _miDiags = new (
  117. "_Diagnostics",
  118. "",
  119. () => ToggleDiagnostics ()
  120. )
  121. {
  122. Checked = View.Diagnostics
  123. == (ViewDiagnosticFlags
  124. .Padding
  125. | ViewDiagnosticFlags
  126. .Ruler),
  127. CheckType = MenuItemCheckStyle.Checked
  128. }
  129. }
  130. )
  131. ]
  132. };
  133. app.Add (menu);
  134. _graphView = new()
  135. {
  136. X = 0,
  137. Y = 1,
  138. Width = Dim.Percent (70),
  139. Height = Dim.Fill (1),
  140. BorderStyle = LineStyle.Single
  141. };
  142. _graphView.Border.Thickness = _thickness;
  143. _graphView.Margin.Thickness = _thickness;
  144. _graphView.Padding.Thickness = _thickness;
  145. app.Add (_graphView);
  146. var frameRight = new FrameView
  147. {
  148. X = Pos.Right (_graphView),
  149. Y = Pos.Top (_graphView),
  150. Width = Dim.Fill (),
  151. Height = Dim.Height (_graphView),
  152. Title = "About"
  153. };
  154. frameRight.Add (
  155. _about = new() { Width = Dim.Fill (), Height = Dim.Fill (), ReadOnly = true }
  156. );
  157. app.Add (frameRight);
  158. var statusBar = new StatusBar (
  159. new Shortcut []
  160. {
  161. new (Key.G.WithCtrl, "Next Graph", () => _graphs [_currentGraph++ % _graphs.Length] ()),
  162. new (Key.PageUp, "Zoom In", () => Zoom (0.5f)),
  163. new (Key.PageDown, "Zoom Out", () => Zoom (2f))
  164. }
  165. );
  166. app.Add (statusBar);
  167. var diagShortcut = new Shortcut
  168. {
  169. Key = Key.F10,
  170. CommandView = new CheckBox
  171. {
  172. Title = "Diagnostics",
  173. CanFocus = false
  174. }
  175. };
  176. statusBar.Add (diagShortcut).Accepting += DiagShortcut_Accept;
  177. _graphs [_currentGraph++ % _graphs.Length] ();
  178. _viewDiagnostics = View.Diagnostics;
  179. Application.Run (app);
  180. View.Diagnostics = _viewDiagnostics;
  181. app.Dispose ();
  182. Application.Shutdown ();
  183. }
  184. private void DiagShortcut_Accept (object sender, CommandEventArgs e)
  185. {
  186. ToggleDiagnostics ();
  187. if (sender is Shortcut shortcut && shortcut.CommandView is CheckBox checkBox)
  188. {
  189. checkBox.CheckedState = _miDiags.Checked ?? false ? CheckState.Checked : CheckState.UnChecked;
  190. }
  191. }
  192. private void ToggleDiagnostics ()
  193. {
  194. _miDiags.Checked = !_miDiags.Checked;
  195. View.Diagnostics = _miDiags.Checked == true
  196. ? ViewDiagnosticFlags.Padding
  197. | ViewDiagnosticFlags.Ruler
  198. : ViewDiagnosticFlags.Off;
  199. Application.Refresh ();
  200. }
  201. private void Margin (bool left, bool increase)
  202. {
  203. if (left)
  204. {
  205. _graphView.MarginLeft = (uint)Math.Max (0, _graphView.MarginLeft + (increase ? 1 : -1));
  206. }
  207. else
  208. {
  209. _graphView.MarginBottom = (uint)Math.Max (0, _graphView.MarginBottom + (increase ? 1 : -1));
  210. }
  211. _graphView.SetNeedsDisplay ();
  212. }
  213. private void MultiBarGraph ()
  214. {
  215. _graphView.Reset ();
  216. _graphView.Title = "Multi Bar";
  217. _about.Text = "Housing Expenditures by income thirds 1996-2003";
  218. Color fore = _graphView.ColorScheme.Normal.Foreground == Color.Black
  219. ? Color.White
  220. : _graphView.ColorScheme.Normal.Foreground;
  221. var black = new Attribute (fore, Color.Black);
  222. var cyan = new Attribute (Color.BrightCyan, Color.Black);
  223. var magenta = new Attribute (Color.BrightMagenta, Color.Black);
  224. var red = new Attribute (Color.BrightRed, Color.Black);
  225. _graphView.GraphColor = black;
  226. var series = new MultiBarSeries (3, 1, 0.25f, new [] { magenta, cyan, red });
  227. Rune stiple = CM.Glyphs.Stipple;
  228. series.AddBars ("'96", stiple, 5900, 9000, 14000);
  229. series.AddBars ("'97", stiple, 6100, 9200, 14800);
  230. series.AddBars ("'98", stiple, 6000, 9300, 14600);
  231. series.AddBars ("'99", stiple, 6100, 9400, 14950);
  232. series.AddBars ("'00", stiple, 6200, 9500, 15200);
  233. series.AddBars ("'01", stiple, 6250, 9900, 16000);
  234. series.AddBars ("'02", stiple, 6600, 11000, 16700);
  235. series.AddBars ("'03", stiple, 7000, 12000, 17000);
  236. _graphView.CellSize = new (0.25f, 1000);
  237. _graphView.Series.Add (series);
  238. _graphView.SetNeedsDisplay ();
  239. _graphView.MarginLeft = 3;
  240. _graphView.MarginBottom = 1;
  241. _graphView.AxisY.LabelGetter = v => '$' + (v.Value / 1000f).ToString ("N0") + 'k';
  242. // Do not show x axis labels (bars draw their own labels)
  243. _graphView.AxisX.Increment = 0;
  244. _graphView.AxisX.ShowLabelsEvery = 0;
  245. _graphView.AxisX.Minimum = 0;
  246. _graphView.AxisY.Minimum = 0;
  247. var legend = new LegendAnnotation (new (_graphView.Viewport.Width - 20, 0, 20, 5));
  248. legend.AddEntry (
  249. new (stiple, series.SubSeries.ElementAt (0).OverrideBarColor),
  250. "Lower Third"
  251. );
  252. legend.AddEntry (
  253. new (stiple, series.SubSeries.ElementAt (1).OverrideBarColor),
  254. "Middle Third"
  255. );
  256. legend.AddEntry (
  257. new (stiple, series.SubSeries.ElementAt (2).OverrideBarColor),
  258. "Upper Third"
  259. );
  260. _graphView.Annotations.Add (legend);
  261. }
  262. private void Quit () { Application.RequestStop (); }
  263. private void SetupDisco ()
  264. {
  265. _graphView.Reset ();
  266. _graphView.Title = "Graphic Equalizer";
  267. _about.Text = "This graph shows a graphic equalizer for an imaginary song";
  268. _graphView.GraphColor = new Attribute (Color.White, Color.Black);
  269. var stiple = new GraphCellToRender ((Rune)'\u2593');
  270. var r = new Random ();
  271. var series = new DiscoBarSeries ();
  272. List<BarSeriesBar> bars = new ();
  273. Func<bool> genSample = () =>
  274. {
  275. bars.Clear ();
  276. // generate an imaginary sample
  277. for (var i = 0; i < 31; i++)
  278. {
  279. bars.Add (
  280. new (null, stiple, r.Next (0, 100))
  281. {
  282. //ColorGetter = colorDelegate
  283. }
  284. );
  285. }
  286. _graphView.SetNeedsDisplay ();
  287. // while the equaliser is showing
  288. return _graphView.Series.Contains (series);
  289. };
  290. Application.AddTimeout (TimeSpan.FromMilliseconds (250), genSample);
  291. series.Bars = bars;
  292. _graphView.Series.Add (series);
  293. // How much graph space each cell of the console depicts
  294. _graphView.CellSize = new (1, 10);
  295. _graphView.AxisX.Increment = 0; // No graph ticks
  296. _graphView.AxisX.ShowLabelsEvery = 0; // no labels
  297. _graphView.AxisX.Visible = false;
  298. _graphView.AxisY.Visible = false;
  299. _graphView.SetNeedsDisplay ();
  300. }
  301. /*
  302. Country,Both,Male,Female
  303. "Switzerland",83.4,81.8,85.1
  304. "South Korea",83.3,80.3,86.1
  305. "Singapore",83.2,81,85.5
  306. "Spain",83.2,80.7,85.7
  307. "Cyprus",83.1,81.1,85.1
  308. "Australia",83,81.3,84.8
  309. "Italy",83,80.9,84.9
  310. "Norway",83,81.2,84.7
  311. "Israel",82.6,80.8,84.4
  312. "France",82.5,79.8,85.1
  313. "Luxembourg",82.4,80.6,84.2
  314. "Sweden",82.4,80.8,84
  315. "Iceland",82.3,80.8,83.9
  316. "Canada",82.2,80.4,84.1
  317. "New Zealand",82,80.4,83.5
  318. "Malta,81.9",79.9,83.8
  319. "Ireland",81.8,80.2,83.5
  320. "Netherlands",81.8,80.4,83.1
  321. "Germany",81.7,78.7,84.8
  322. "Austria",81.6,79.4,83.8
  323. "Finland",81.6,79.2,84
  324. "Portugal",81.6,78.6,84.4
  325. "Belgium",81.4,79.3,83.5
  326. "United Kingdom",81.4,79.8,83
  327. "Denmark",81.3,79.6,83
  328. "Slovenia",81.3,78.6,84.1
  329. "Greece",81.1,78.6,83.6
  330. "Kuwait",81,79.3,83.9
  331. "Costa Rica",80.8,78.3,83.4*/
  332. private void SetupLifeExpectancyBarGraph (bool verticalBars)
  333. {
  334. _graphView.Reset ();
  335. _graphView.Title = $"Life Expectancy - {(verticalBars ? "Vertical" : "Horizontal")}";
  336. _about.Text = "This graph shows the life expectancy at birth of a range of countries";
  337. var softStiple = new GraphCellToRender ((Rune)'\u2591');
  338. var mediumStiple = new GraphCellToRender ((Rune)'\u2592');
  339. var barSeries = new BarSeries
  340. {
  341. Bars = new()
  342. {
  343. new ("Switzerland", softStiple, 83.4f),
  344. new (
  345. "South Korea",
  346. !verticalBars
  347. ? mediumStiple
  348. : softStiple,
  349. 83.3f
  350. ),
  351. new ("Singapore", softStiple, 83.2f),
  352. new (
  353. "Spain",
  354. !verticalBars
  355. ? mediumStiple
  356. : softStiple,
  357. 83.2f
  358. ),
  359. new ("Cyprus", softStiple, 83.1f),
  360. new (
  361. "Australia",
  362. !verticalBars
  363. ? mediumStiple
  364. : softStiple,
  365. 83
  366. ),
  367. new ("Italy", softStiple, 83),
  368. new (
  369. "Norway",
  370. !verticalBars
  371. ? mediumStiple
  372. : softStiple,
  373. 83
  374. ),
  375. new ("Israel", softStiple, 82.6f),
  376. new (
  377. "France",
  378. !verticalBars
  379. ? mediumStiple
  380. : softStiple,
  381. 82.5f
  382. ),
  383. new ("Luxembourg", softStiple, 82.4f),
  384. new (
  385. "Sweden",
  386. !verticalBars
  387. ? mediumStiple
  388. : softStiple,
  389. 82.4f
  390. ),
  391. new ("Iceland", softStiple, 82.3f),
  392. new (
  393. "Canada",
  394. !verticalBars
  395. ? mediumStiple
  396. : softStiple,
  397. 82.2f
  398. ),
  399. new ("New Zealand", softStiple, 82),
  400. new (
  401. "Malta",
  402. !verticalBars
  403. ? mediumStiple
  404. : softStiple,
  405. 81.9f
  406. ),
  407. new ("Ireland", softStiple, 81.8f)
  408. }
  409. };
  410. _graphView.Series.Add (barSeries);
  411. if (verticalBars)
  412. {
  413. barSeries.Orientation = Orientation.Vertical;
  414. // How much graph space each cell of the console depicts
  415. _graphView.CellSize = new (0.1f, 0.25f);
  416. // No axis marks since Bar will add it's own categorical marks
  417. _graphView.AxisX.Increment = 0f;
  418. _graphView.AxisX.Text = "Country";
  419. _graphView.AxisX.Minimum = 0;
  420. _graphView.AxisY.Increment = 1f;
  421. _graphView.AxisY.ShowLabelsEvery = 1;
  422. _graphView.AxisY.LabelGetter = v => v.Value.ToString ("N2");
  423. _graphView.AxisY.Minimum = 0;
  424. _graphView.AxisY.Text = "Age";
  425. // leave space for axis labels and title
  426. _graphView.MarginBottom = 2;
  427. _graphView.MarginLeft = 6;
  428. // Start the graph at 80 years because that is where most of our data is
  429. _graphView.ScrollOffset = new (0, 80);
  430. }
  431. else
  432. {
  433. barSeries.Orientation = Orientation.Horizontal;
  434. // How much graph space each cell of the console depicts
  435. _graphView.CellSize = new (0.1f, 1f);
  436. // No axis marks since Bar will add it's own categorical marks
  437. _graphView.AxisY.Increment = 0f;
  438. _graphView.AxisY.ShowLabelsEvery = 1;
  439. _graphView.AxisY.Text = "Country";
  440. _graphView.AxisY.Minimum = 0;
  441. _graphView.AxisX.Increment = 1f;
  442. _graphView.AxisX.ShowLabelsEvery = 1;
  443. _graphView.AxisX.LabelGetter = v => v.Value.ToString ("N2");
  444. _graphView.AxisX.Text = "Age";
  445. _graphView.AxisX.Minimum = 0;
  446. // leave space for axis labels and title
  447. _graphView.MarginBottom = 2;
  448. _graphView.MarginLeft = (uint)barSeries.Bars.Max (b => b.Text.Length) + 2;
  449. // Start the graph at 80 years because that is where most of our data is
  450. _graphView.ScrollOffset = new (80, 0);
  451. }
  452. _graphView.SetNeedsDisplay ();
  453. }
  454. private void SetupLineGraph ()
  455. {
  456. _graphView.Reset ();
  457. _graphView.Title = "Line";
  458. _about.Text = "This graph shows random points";
  459. var black = new Attribute (_graphView.ColorScheme.Normal.Foreground, Color.Black);
  460. var cyan = new Attribute (Color.BrightCyan, Color.Black);
  461. var magenta = new Attribute (Color.BrightMagenta, Color.Black);
  462. var red = new Attribute (Color.BrightRed, Color.Black);
  463. _graphView.GraphColor = black;
  464. List<PointF> randomPoints = new ();
  465. var r = new Random ();
  466. for (var i = 0; i < 10; i++)
  467. {
  468. randomPoints.Add (new (r.Next (100), r.Next (100)));
  469. }
  470. var points = new ScatterSeries { Points = randomPoints };
  471. var line = new PathAnnotation
  472. {
  473. LineColor = cyan, Points = randomPoints.OrderBy (p => p.X).ToList (), BeforeSeries = true
  474. };
  475. _graphView.Series.Add (points);
  476. _graphView.Annotations.Add (line);
  477. randomPoints = new ();
  478. for (var i = 0; i < 10; i++)
  479. {
  480. randomPoints.Add (new (r.Next (100), r.Next (100)));
  481. }
  482. var points2 = new ScatterSeries { Points = randomPoints, Fill = new ((Rune)'x', red) };
  483. var line2 = new PathAnnotation
  484. {
  485. LineColor = magenta, Points = randomPoints.OrderBy (p => p.X).ToList (), BeforeSeries = true
  486. };
  487. _graphView.Series.Add (points2);
  488. _graphView.Annotations.Add (line2);
  489. // How much graph space each cell of the console depicts
  490. _graphView.CellSize = new (2, 5);
  491. // leave space for axis labels
  492. _graphView.MarginBottom = 2;
  493. _graphView.MarginLeft = 3;
  494. // One axis tick/label per
  495. _graphView.AxisX.Increment = 20;
  496. _graphView.AxisX.ShowLabelsEvery = 1;
  497. _graphView.AxisX.Text = "X →";
  498. _graphView.AxisY.Increment = 20;
  499. _graphView.AxisY.ShowLabelsEvery = 1;
  500. _graphView.AxisY.Text = "↑Y";
  501. PointF max = line.Points.Union (line2.Points).OrderByDescending (p => p.Y).First ();
  502. _graphView.Annotations.Add (
  503. new TextAnnotation
  504. {
  505. Text = "(Max)",
  506. GraphPosition = new (
  507. max.X + 2 * _graphView.CellSize.X,
  508. max.Y
  509. )
  510. }
  511. );
  512. _graphView.SetNeedsDisplay ();
  513. }
  514. private void SetupPeriodicTableScatterPlot ()
  515. {
  516. _graphView.Reset ();
  517. _graphView.Title = "Scatter Plot";
  518. _about.Text =
  519. "This graph shows the atomic weight of each element in the periodic table.\nStarting with Hydrogen (atomic Number 1 with a weight of 1.007)";
  520. //AtomicNumber and AtomicMass of all elements in the periodic table
  521. _graphView.Series.Add (
  522. new ScatterSeries
  523. {
  524. Points = new()
  525. {
  526. new (1, 1.007f),
  527. new (2, 4.002f),
  528. new (3, 6.941f),
  529. new (4, 9.012f),
  530. new (5, 10.811f),
  531. new (6, 12.011f),
  532. new (7, 14.007f),
  533. new (8, 15.999f),
  534. new (9, 18.998f),
  535. new (10, 20.18f),
  536. new (11, 22.99f),
  537. new (12, 24.305f),
  538. new (13, 26.982f),
  539. new (14, 28.086f),
  540. new (15, 30.974f),
  541. new (16, 32.065f),
  542. new (17, 35.453f),
  543. new (18, 39.948f),
  544. new (19, 39.098f),
  545. new (20, 40.078f),
  546. new (21, 44.956f),
  547. new (22, 47.867f),
  548. new (23, 50.942f),
  549. new (24, 51.996f),
  550. new (25, 54.938f),
  551. new (26, 55.845f),
  552. new (27, 58.933f),
  553. new (28, 58.693f),
  554. new (29, 63.546f),
  555. new (30, 65.38f),
  556. new (31, 69.723f),
  557. new (32, 72.64f),
  558. new (33, 74.922f),
  559. new (34, 78.96f),
  560. new (35, 79.904f),
  561. new (36, 83.798f),
  562. new (37, 85.468f),
  563. new (38, 87.62f),
  564. new (39, 88.906f),
  565. new (40, 91.224f),
  566. new (41, 92.906f),
  567. new (42, 95.96f),
  568. new (43, 98f),
  569. new (44, 101.07f),
  570. new (45, 102.906f),
  571. new (46, 106.42f),
  572. new (47, 107.868f),
  573. new (48, 112.411f),
  574. new (49, 114.818f),
  575. new (50, 118.71f),
  576. new (51, 121.76f),
  577. new (52, 127.6f),
  578. new (53, 126.904f),
  579. new (54, 131.293f),
  580. new (55, 132.905f),
  581. new (56, 137.327f),
  582. new (57, 138.905f),
  583. new (58, 140.116f),
  584. new (59, 140.908f),
  585. new (60, 144.242f),
  586. new (61, 145),
  587. new (62, 150.36f),
  588. new (63, 151.964f),
  589. new (64, 157.25f),
  590. new (65, 158.925f),
  591. new (66, 162.5f),
  592. new (67, 164.93f),
  593. new (68, 167.259f),
  594. new (69, 168.934f),
  595. new (70, 173.054f),
  596. new (71, 174.967f),
  597. new (72, 178.49f),
  598. new (73, 180.948f),
  599. new (74, 183.84f),
  600. new (75, 186.207f),
  601. new (76, 190.23f),
  602. new (77, 192.217f),
  603. new (78, 195.084f),
  604. new (79, 196.967f),
  605. new (80, 200.59f),
  606. new (81, 204.383f),
  607. new (82, 207.2f),
  608. new (83, 208.98f),
  609. new (84, 210),
  610. new (85, 210),
  611. new (86, 222),
  612. new (87, 223),
  613. new (88, 226),
  614. new (89, 227),
  615. new (90, 232.038f),
  616. new (91, 231.036f),
  617. new (92, 238.029f),
  618. new (93, 237),
  619. new (94, 244),
  620. new (95, 243),
  621. new (96, 247),
  622. new (97, 247),
  623. new (98, 251),
  624. new (99, 252),
  625. new (100, 257),
  626. new (101, 258),
  627. new (102, 259),
  628. new (103, 262),
  629. new (104, 261),
  630. new (105, 262),
  631. new (106, 266),
  632. new (107, 264),
  633. new (108, 267),
  634. new (109, 268),
  635. new (113, 284),
  636. new (114, 289),
  637. new (115, 288),
  638. new (116, 292),
  639. new (117, 295),
  640. new (118, 294)
  641. }
  642. }
  643. );
  644. // How much graph space each cell of the console depicts
  645. _graphView.CellSize = new (1, 5);
  646. // leave space for axis labels
  647. _graphView.MarginBottom = 2;
  648. _graphView.MarginLeft = 3;
  649. // One axis tick/label per 5 atomic numbers
  650. _graphView.AxisX.Increment = 5;
  651. _graphView.AxisX.ShowLabelsEvery = 1;
  652. _graphView.AxisX.Text = "Atomic Number";
  653. _graphView.AxisX.Minimum = 0;
  654. // One label every 5 atomic weight
  655. _graphView.AxisY.Increment = 5;
  656. _graphView.AxisY.ShowLabelsEvery = 1;
  657. _graphView.AxisY.Minimum = 0;
  658. _graphView.SetNeedsDisplay ();
  659. }
  660. private void SetupPopulationPyramid ()
  661. {
  662. /*
  663. Age,M,F
  664. 0-4,2009363,1915127
  665. 5-9,2108550,2011016
  666. 10-14,2022370,1933970
  667. 15-19,1880611,1805522
  668. 20-24,2072674,2001966
  669. 25-29,2275138,2208929
  670. 30-34,2361054,2345774
  671. 35-39,2279836,2308360
  672. 40-44,2148253,2159877
  673. 45-49,2128343,2167778
  674. 50-54,2281421,2353119
  675. 55-59,2232388,2306537
  676. 60-64,1919839,1985177
  677. 65-69,1647391,1734370
  678. 70-74,1624635,1763853
  679. 75-79,1137438,1304709
  680. 80-84,766956,969611
  681. 85-89,438663,638892
  682. 90-94,169952,320625
  683. 95-99,34524,95559
  684. 100+,3016,12818*/
  685. _about.Text = "This graph shows population of each age divided by gender";
  686. _graphView.Title = "Population Pyramid";
  687. _graphView.Reset ();
  688. // How much graph space each cell of the console depicts
  689. _graphView.CellSize = new (100_000, 1);
  690. //center the x axis in middle of screen to show both sides
  691. _graphView.ScrollOffset = new (-3_000_000, 0);
  692. _graphView.AxisX.Text = "Number Of People";
  693. _graphView.AxisX.Increment = 500_000;
  694. _graphView.AxisX.ShowLabelsEvery = 2;
  695. // use Abs to make negative axis labels positive
  696. _graphView.AxisX.LabelGetter = v => Math.Abs (v.Value / 1_000_000).ToString ("N2") + "M";
  697. // leave space for axis labels
  698. _graphView.MarginBottom = 2;
  699. _graphView.MarginLeft = 1;
  700. // do not show axis titles (bars have their own categories)
  701. _graphView.AxisY.Increment = 0;
  702. _graphView.AxisY.ShowLabelsEvery = 0;
  703. _graphView.AxisY.Minimum = 0;
  704. var stiple = new GraphCellToRender (CM.Glyphs.Stipple);
  705. // Bars in 2 directions
  706. // Males (negative to make the bars go left)
  707. var malesSeries = new BarSeries
  708. {
  709. Orientation = Orientation.Horizontal,
  710. Bars = new()
  711. {
  712. new ("0-4", stiple, -2009363),
  713. new ("5-9", stiple, -2108550),
  714. new ("10-14", stiple, -2022370),
  715. new ("15-19", stiple, -1880611),
  716. new ("20-24", stiple, -2072674),
  717. new ("25-29", stiple, -2275138),
  718. new ("30-34", stiple, -2361054),
  719. new ("35-39", stiple, -2279836),
  720. new ("40-44", stiple, -2148253),
  721. new ("45-49", stiple, -2128343),
  722. new ("50-54", stiple, -2281421),
  723. new ("55-59", stiple, -2232388),
  724. new ("60-64", stiple, -1919839),
  725. new ("65-69", stiple, -1647391),
  726. new ("70-74", stiple, -1624635),
  727. new ("75-79", stiple, -1137438),
  728. new ("80-84", stiple, -766956),
  729. new ("85-89", stiple, -438663),
  730. new ("90-94", stiple, -169952),
  731. new ("95-99", stiple, -34524),
  732. new ("100+", stiple, -3016)
  733. }
  734. };
  735. _graphView.Series.Add (malesSeries);
  736. // Females
  737. var femalesSeries = new BarSeries
  738. {
  739. Orientation = Orientation.Horizontal,
  740. Bars = new()
  741. {
  742. new ("0-4", stiple, 1915127),
  743. new ("5-9", stiple, 2011016),
  744. new ("10-14", stiple, 1933970),
  745. new ("15-19", stiple, 1805522),
  746. new ("20-24", stiple, 2001966),
  747. new ("25-29", stiple, 2208929),
  748. new ("30-34", stiple, 2345774),
  749. new ("35-39", stiple, 2308360),
  750. new ("40-44", stiple, 2159877),
  751. new ("45-49", stiple, 2167778),
  752. new ("50-54", stiple, 2353119),
  753. new ("55-59", stiple, 2306537),
  754. new ("60-64", stiple, 1985177),
  755. new ("65-69", stiple, 1734370),
  756. new ("70-74", stiple, 1763853),
  757. new ("75-79", stiple, 1304709),
  758. new ("80-84", stiple, 969611),
  759. new ("85-89", stiple, 638892),
  760. new ("90-94", stiple, 320625),
  761. new ("95-99", stiple, 95559),
  762. new ("100+", stiple, 12818)
  763. }
  764. };
  765. var softStiple = new GraphCellToRender ((Rune)'\u2591');
  766. var mediumStiple = new GraphCellToRender ((Rune)'\u2592');
  767. for (var i = 0; i < malesSeries.Bars.Count; i++)
  768. {
  769. malesSeries.Bars [i].Fill = i % 2 == 0 ? softStiple : mediumStiple;
  770. femalesSeries.Bars [i].Fill = i % 2 == 0 ? softStiple : mediumStiple;
  771. }
  772. _graphView.Series.Add (femalesSeries);
  773. _graphView.Annotations.Add (new TextAnnotation { Text = "M", ScreenPosition = new Point (0, 10) });
  774. _graphView.Annotations.Add (
  775. new TextAnnotation { Text = "F", ScreenPosition = new Point (_graphView.Viewport.Width - 1, 10) }
  776. );
  777. _graphView.SetNeedsDisplay ();
  778. }
  779. private void SetupSineWave ()
  780. {
  781. _graphView.Reset ();
  782. _graphView.Title = "Sine Wave";
  783. _about.Text = "This graph shows a sine wave";
  784. var points = new ScatterSeries ();
  785. var line = new PathAnnotation ();
  786. // Draw line first so it does not draw over top of points or axis labels
  787. line.BeforeSeries = true;
  788. // Generate line graph with 2,000 points
  789. for (float x = -500; x < 500; x += 0.5f)
  790. {
  791. points.Points.Add (new (x, (float)Math.Sin (x)));
  792. line.Points.Add (new (x, (float)Math.Sin (x)));
  793. }
  794. _graphView.Series.Add (points);
  795. _graphView.Annotations.Add (line);
  796. // How much graph space each cell of the console depicts
  797. _graphView.CellSize = new (0.1f, 0.1f);
  798. // leave space for axis labels
  799. _graphView.MarginBottom = 2;
  800. _graphView.MarginLeft = 3;
  801. // One axis tick/label per
  802. _graphView.AxisX.Increment = 0.5f;
  803. _graphView.AxisX.ShowLabelsEvery = 2;
  804. _graphView.AxisX.Text = "X →";
  805. _graphView.AxisX.LabelGetter = v => v.Value.ToString ("N2");
  806. _graphView.AxisY.Increment = 0.2f;
  807. _graphView.AxisY.ShowLabelsEvery = 2;
  808. _graphView.AxisY.Text = "↑Y";
  809. _graphView.AxisY.LabelGetter = v => v.Value.ToString ("N2");
  810. _graphView.ScrollOffset = new (-2.5f, -1);
  811. _graphView.SetNeedsDisplay ();
  812. }
  813. private void ShowBorder ()
  814. {
  815. _miShowBorder.Checked = !_miShowBorder.Checked;
  816. if (_miShowBorder.Checked == true)
  817. {
  818. _graphView.BorderStyle = LineStyle.Single;
  819. _graphView.Border.Thickness = _thickness;
  820. _graphView.Margin.Thickness = _thickness;
  821. _graphView.Padding.Thickness = _thickness;
  822. }
  823. else
  824. {
  825. _graphView.BorderStyle = LineStyle.None;
  826. _graphView.Margin.Thickness = Thickness.Empty;
  827. _graphView.Padding.Thickness = Thickness.Empty;
  828. }
  829. }
  830. private void Zoom (float factor)
  831. {
  832. _graphView.CellSize = new (
  833. _graphView.CellSize.X * factor,
  834. _graphView.CellSize.Y * factor
  835. );
  836. _graphView.AxisX.Increment *= factor;
  837. _graphView.AxisY.Increment *= factor;
  838. _graphView.SetNeedsDisplay ();
  839. }
  840. private class DiscoBarSeries : BarSeries
  841. {
  842. private readonly Attribute _brightgreen;
  843. private readonly Attribute _brightred;
  844. private readonly Attribute _brightyellow;
  845. private readonly Attribute _green;
  846. private readonly Attribute _red;
  847. public DiscoBarSeries ()
  848. {
  849. _green = new (Color.BrightGreen, Color.Black);
  850. _brightgreen = new (Color.Green, Color.Black);
  851. _brightyellow = new (Color.BrightYellow, Color.Black);
  852. _red = new (Color.Red, Color.Black);
  853. _brightred = new (Color.BrightRed, Color.Black);
  854. }
  855. protected override void DrawBarLine (GraphView graph, Point start, Point end, BarSeriesBar beingDrawn)
  856. {
  857. ConsoleDriver driver = Application.Driver;
  858. int x = start.X;
  859. for (int y = end.Y; y <= start.Y; y++)
  860. {
  861. float height = graph.ScreenToGraphSpace (x, y).Y;
  862. if (height >= 85)
  863. {
  864. driver.SetAttribute (_red);
  865. }
  866. else if (height >= 66)
  867. {
  868. driver.SetAttribute (_brightred);
  869. }
  870. else if (height >= 45)
  871. {
  872. driver.SetAttribute (_brightyellow);
  873. }
  874. else if (height >= 25)
  875. {
  876. driver.SetAttribute (_brightgreen);
  877. }
  878. else
  879. {
  880. driver.SetAttribute (_green);
  881. }
  882. graph.AddRune (x, y, beingDrawn.Fill.Rune);
  883. }
  884. }
  885. }
  886. }