GraphViewExample.cs 37 KB

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