Sign in Join
Wiki copytemporary

TAChart Tutorial: Dual y axis, Legend/fi: what changed

Revision 0 to 1. Removed lines have a minus sign; added lines have a plus sign.

Title: TAChart Tutorial: Dual y axis, Legend/fi

OldNewLine
1+## Johdanto
2+
3+![](/wiki-images/4/47/TAChart_DualYAxis11.png)
4+
5+Kun erilaisia suureita piirretään samaan kaavioon niin tapahtuu melko usein, että niiden suurusluokat ovat eri alueella. "Tavallisessa" kaaviossa kuvaajia hallitsee suuret arvot pienten arvojen kustannuksella jotka "puristuu" tasaiseksi viivaksi. Kaaviolla olisi paljon enemmän merkitystä, jos erilaisia akseleita voidaan käyttää, yhdellä olisi isoja arvoja ja toisella pieniä arvoja.
6+
7+Kun olet käynyt läpi opetusohjelman [[TAChart Tutorial: Userdefined ChartSource/fi|käyttäjän määrittämä chartsource]] olet törmännyt tällaiseen tapaukseen. Siinä opetusohjelmassa tehtiin kaavio maailman väestöstä iän funktiona. Siinä on myös mahdollisuus nähdä miesten ja naisten määrien välinen suhde. Tämä jälkimmäinen luku on huomattavasti pienempi kuin väestön määrä. Joten, jos molemmat tiedot yhdistettäisiin samaan kaavion niin väestö suhde olisi kutistunut vaakasuoraksi viivaksi
8+
9+Tämä on taustana tähän projektiin. Katsotaan väestön tiedot uudelleen, piirretään väkiluku ja mies-nais suhde samaan kaavioon.
10+
11+Opit miten
12+
13+- luoda kaavion, jossa on **kaksi y-akselia**
14+- käyttää automaattista skaalausta akselin asteikko muunnoksessa
15+- tehdään käyttäjän muokkaamia akselin merkintöjä
16+- tehdään kuvaajien otsikkopalkki (legend) käyttämällä vähemmän tunnettuja ominaisuuksia.
17+
18+Kuten tavallista niin sinun tulisi tuntea Lazarus ja FPC sekä pitäisi olla perustiedot TAChart kirjastosta (käy ensin läpi [[TAChart Tutorial: Getting started/fi|TAChart:n aloitus opetusohjelma]] ). Tässä nimenomaisessa opetusohjelmassa olisi myös hyödyllistä, jos olisit tutkinut opetusohjelman [[TAChart Tutorial: Userdefined ChartSource/fi|käyttäjän määrittämiä chartsource]] ensin.
19+
20+## Data
21+
22+Kuten jo mainittiin käytämme samoja tietoja kuin [[TAChart Tutorial: Userdefined ChartSource/fi|käyttäjän määrittämä chartsource]] opetusohjelmassa. Ensisijainen datatiedosto on nimeltään "`population.txt`" ja peräisin [www.census.gov](http://www.census.gov/population/international/data/worldpop/tool_population.php). Kopioi tämä tiedosto [[TAChart Tutorial: Userdefined ChartSource/fi|käyttäjän määrittämä chartsource]] opetusohjelma projektin hakemistosta tai seuraa siellä olevia ohjeita miten ladata tiedosto. Käännösyksikkö population.pas lukee tämän tiedoston ja tallentaa tiedot tietueiden `TPopulationRecord`taulukkoon
23+
24+``` pascal
25+type
26+ TPopulationRecord = record
27+ Age: Integer;
28+ Total: Double;
29+ Male: Double;
30+ Female: Double;
31+ Ratio: Double;
32+ end;
33+
34+ TPopulationArray = array of TPopulationRecord;
35+```
36+
37+Nyt on kaikki mitä tarvitaan jotta voidaan aloittaa uuden projektin. Lisää käännösyksikkö population.pas lomakkeen uses luetteloon. Lisää muuttujan `PopulationData` tyyppiä `TPopulationArray` esittely lomakkeen `private` osaan. Ja datatiedoston lukemisen kutsu `LoadPopulationData` (joka on population unit käännösyksikössä) lomakkeen `OnCreate` tapahtumaan:
38+
39+``` pascal
40+uses
41+ ..., population, ...;
42+
43+type
44+ TForm1 = class(TForm)
45+ // ...
46+ private
47+ PopulationData : TPopulationArray;
48+ // ...
49+ end;
50+
51+const
52+ POPULATION_FILE = 'population.txt';
53+
54+procedure TForm1.FormCreate(Sender: TObject);
55+begin
56+ LoadPopulationData(POPULATION_FILE, PopulationData);
57+end;
58+```
59+
60+## Kaavion valmistelu
61+
62+Nyt voidaan aloittaa kaavion valmistelu...
63+
64+Lisää **`TChart`** komponentti lomakkeelle:
65+
66+- Aseta sen Align ominaisuus arvoon `alClient`.
67+- Aseta sen `BackColor` arvoon `clWhite`.
68+
69+Lisää **kolme viivakuvaajaa** kaavioon:
70+
71+- Vaihda niiden nimet kuvailemmiksi `LineSeries_male`, `LineSeries_female` ja `LineSeries_ratio`.
72+- Aseta `SeriesColor` väri kuvaajalla `LineSeries_male` arvoon `clSkyBlue`, kuvaajalla `LineSeries_female` arvoon `$00FF80FF` ja jätä `LineSeries_ratio` kuvaajan väri mustaksi.
73+
74+Mistä kuvaajat saavat tietonsa? Tiedot on tallennettu `PopulationData` taulukkoon, joten se olisi parasta hyödyntää [[TAChart documentation|käyttäjän määrittämä kaavio lähde]] . Tarkasti ottaen: tarvitaan kolme kaavion lähdettä, yksi kutakin kuvaajaa kohti.
75+
76+Siksi lisää kolme `TUserDefinedChartSource` -komponenttia lomakkeelle:
77+
78+- Nimetään ne kuvaammaksi `ChartSource_male`, `ChartSource_female` ja `ChartSource_ratio`.
79+- Aseta kunkin chartsource ominaisuus `Source` vastaamaan oikeata viivakuvaajaa.
80+- Kirjoitetaan seuraava tapahtumankäsittelijä ja liitetään se kunkin user-defined chart source:n `OnGetDataItem` tapahtumaan:
81+
82+``` pascal
83+procedure TForm1.ChartSourceGetChartDataItem(
84+ ASource: TUserDefinedChartSource; AIndex: Integer; var AItem: TChartDataItem);
85+begin
86+ AItem.X := PopulationData[AIndex].Age;
87+ if ASource = ChartSource_male then
88+ AItem.Y := PopulationData[AIndex].Male / 1e6
89+ else if ASource = ChartSource_female then
90+ AItem.Y := PopulationData[AIndex].Female / 1e6
91+ else
92+ AItem.Y := PopulationData[AIndex].Ratio / 100;
93+end;
94+```
95+
96+Seuraavaksi kerrotaan kaavion datan lähde, josta ottaa datan: x: n arvo on otettu tietueen `TPopulationRecord` kentästä `Age`, ja riippuen kaavion datalähteestä, y:n arvo otetaan tietueen `TPopulationRecord` kentistä `Male`, `Female` tai `Ratio`.
97+
98+Väkiluku jaetaan miljoonalla jolloin päästään eroon monista nollista. Joten pitää muistaa kertoa että väestöakselilla luvut ovat miljoonia. Myös mies-naissuhde jaetaan 100:lla koska käytetään vain jakojäännöksiä, ei prosentteja.
99+
100+Onko jo aika kääntää? Ei, ei vielä. Vielä on kerrottava kaavion lähteissä datapisteiden lukumäärä. Tämä tieto saadaan tiedoston lukemisen jälkeen. Aseteaan ominaisuus `PointNumber` kunkin kaavion datalähteen taulukon pituuden mukaiseksi lomakkeen `OnCreate` tapahtumakäsittelyssä:
101+
102+``` pascal
103+procedure TForm1.FormCreate(Sender: TObject);
104+begin
105+ LoadPopulationData(POPULATION_FILE, PopulationData);
106+ ChartSource_male.PointsNumber := Length(PopulationData);
107+ ChartSource_female.PointsNumber := Length(PopulationData);
108+ ChartSource_ratio.PointsNumber := Length(PopulationData);
109+end;
110+```
111+
112+Tässä vaiheessa lomake ja objekti puu pitäisi näyttää tältä:
113+
114+![](/wiki-images/1/18/TAChart_DualYAxis1.png) ![](/wiki-images/1/1b/TAChart_DualYAxis2.png)
115+
116+ja kun tuon kääntää ja ajaa niin tuloksen pitäisi näyttää joltain tämäntapaiselta:
117+
118+![](/wiki-images/b/bb/TAChart_DualYAxis3.png)
119+
120+Kuten johdannossa mainittiin, mies-nais suhde - joka on musta viiva - on erittäin tasainen. Tämä johtuu arvojen erisuuruidesta: väestön määrä menee melkein nollasta 70:n, kun suhde on lähes aina noin yksi.
121+
122+## Asetetaan toinen y-akseli
123+
124+Tarvitaan toinen y-akseli.
125+
126+Tätä varten siirry objektipuuhun, klikkaa hiiren oikealla `AxisList` (oikealla `Chart1`:n alla ) ja lisää uusi akseli kaavioon. Nyt meillä on kolme akselia:
127+
128+![](/wiki-images/c/c4/TAChart_DualYAxis4.png)
129+
130+Valitse akseli \#2, joka on vielä vasen akseli tällä hetkellä ja aseta komponenttimuokkaimessa sen `Alignment` arvoon `calRight`.
131+
132+Tämä on ehkä hyvä paikka mainita, että kaksi y-akselia ei ole maksimi. Akseleiden määrää voi lisätä kaavion `AxisList` kohtaan. Niitä voidaan käyttää pystyakseleina vasemmalle tai oikealle tai vaaka-akseleina kaavion yläreunassa tai alareunassa. Tutustu akselin parametriin [[TAChart documentation|Group]]: saman ryhmän akselit piirretään samaan suorakulmion, akselien eri ryhmän arvot on piirretty side-by-side.
133+
134+Miten kaavio tietää, mikä kuvaaja kuuluu mihinkin akseliin? Tätä tarkoitusta varten kullakin kuvaajalla on ominaisuuksia `AxisIndexX` ja `AxisIndexY`. Koska miesten ja naisten kuvaajat piirretään vasemman akselin mukaan asetetaan `AxisIndexY` arvoon 0 - katsomalla objektipuusta nähdään, että tämä indeksi kuuluu vasemmalle akselille. Suhde kuvaaja kuuluu oikealle akselille, sen `AxisIndexY` on oltava 2. Voisimme myös asettaa akselin indeksin ala-akselille, mutta tämä ei ole välttämätöntä tässä.
135+
136+Kun tämä käännetään niin tulos on hieman pettymys: ei muutosta - musta suhde-kuvaaja on edelleen hyvin tasainen.
137+
138+![](/wiki-images/b/b4/TAChart_DualYAxis5.png)
139+
140+## Akselin asettaminen automaattisesti muuttuvaan mittakaavaan
141+
142+Syy siihen, miksi toinen y-akseli ei skaalaudu riippumattomasti ensimmäiseen on se, että ohittaa sisäisten koordinaattijärjestelmän. TAChart käyttää kolmea koordinaattijärjestelmää siirrettäessä "reaalimaailman" dataa pikseleihin ruudulle:
143+
144+- [[TAChart documentation|akselin koordinaatit]] ovat koordinaatit, jossa tiedot tulevat tai toisin sanoen, ne jotka on merkitty akselille. Esimerkiksi tässä projektissa nämä ovat väestön määrä (miljoonalla jaon jälkeen), eli numerot välillä 0 - 70.
145+- [[TAChart documentation|kaavio koordinaatit]] saadaan sovittamisen jälkeen tehdyistä muutoksista. On olemassa toinen opetusohjelma, jossa käytetään logaritminen muunnosta, tässä tapauksessa kuvaajan koordinaatit olisivat lähtötietoja logaritmille.
146+- [[TAChart documentation|kuva koordinaatit]] kuuluvat pikseliä ruudulla lasketaan kuvaajan koordinaatteja.
147+
148+Niin, on olemassa kaksi muunnostoimintoa mukana laskettaessa koordinaattien datapisteet näytölle:
149+
150+1. akselin koordinaatit näytön koordinaatteihin käyttäjän määrittelemän `TChartAxisTransform` avulla
151+2. näytön koordinaatit kuvan koordinaateiksi yksinkertaisella lineaarikuvauksen avulla
152+
153+Jos akselin siirtymistä akselista kaavion koordinaatteihin ei ole määritelty niin käytetään yksinkertaista 1: 1 muunnosta.
154+
155+Ai niin - käytössä ei ole mitään akselin muunnosta. Siksi *väestö ja*mies/nais-suhde'' tiedot ovat edelleen yhteisen maailman koordinaateissa. Jos halutaan erottaa kaksi tietokokonaisuutta meidän soveltaa muunnosta jokaiselle tietokokonaisuudelle, joka kuvaa sitä samaa aluetta kuvaajan koordinaattien vaikkapa 0-1.
156+
157+Tätä tarkoitusta varten TAChart on [[TAChart documentation|TAutoScaleAxisTransform]]. Siihen ei ole suoraa pääsyä komponenttipaletilta, mutta sen lapsi löytyy: [[TAChart documentation|TChartAxisTransformations]] -komponentti.
158+
159+Joten, vedä ja pudota kaksi `TChartAxisTransformations` komponenttia lomakkeelle, yksi vasemmalle akselille, yksi oikealle akselille. Nimeä ne `LeftAxisTransformations` ja `RightAxisTransformations` , vastaavasti. Kaksoisnapsauta kutakin näistä komponenteista ja valitse *"Automaattinen skaalaus"* (*"auto scale"*) *Muokkaa akselimuunnoksia* (*axis transformations*)-editorista. Objektipuusta, näet kunkin `ChartAxisTransformations` komponentin lapsen. Nimeä nämä lapset `LeftAxisAutoscaleTransform` ja `RightAxisAutoscaleTransform` , vastaavasti. Aseta `LeftAxisTransformations` ja `RightAxisTransformations` vastaavasti akselien Left (vasemman) ja Right (oikea) ominaisuuteen `Transformations` .
160+
161+Tältä näyttää objektipuu näiden käsittelyiden jälkeen:
162+
163+![](/wiki-images/e/ea/TAChart_DualYAxis6.png)
164+
165+Katso `AutoScaleAxisTransforms` :n ominaisuudet `MaxValue` ja `MinValue`. Molemmilla muunnokset ovat samat `MaxValue = 1` ja `MinValue = 0`. Tämä tarkoittaa, että kukin akseli on sijoitettu välille 0 ja 1, toisin sanoen, molempia aineistoja puristetaan tai laajennetaan täyttämään kaavion alue kokonaan.
166+
167+Kun käännetään ja ajetaan ohjelma niin silloin nähdään mitä tarkalleen tapahtuu.
168+
169+![](/wiki-images/1/1f/TAChart_DualYAxis7.png)
170+
171+Voisimme myös esimerkiksi asettaa `RightAxisAutoscaleTransform` ominaisuudet `MinValue=1` ja `MaxValue=2` . Sitten väestötiedot olisi edelleen kartoitettu akselille 0-1, ja mies-nais suhde data olisi kartoitettu alueelle 1-2, eli meillä olisi paned kaavio, jossa alempi puolisko näyttäisi *väestön* kuvaajat ja ylempi puoli *suhde* kuvaajan. Mutta se kuuluu toiseen opetusohjelmaan. Jätämme `MinValue` ja `MaxValue` ominaisuudet oletusarvoihin.
172+
173+## Hieno viilaus
174+
175+Vaikein osa on tehty nyt. Jäljellä on vielä kaavion "heino viilaus".
176+
177+- Poista akseliruudukko (tämä on jo aikaisemmin opetettu). Vasemman ja oikeamman akselin viivat tekevät siitä hyvin sekavan
178+- Lisää **akseleiden otsikot**:
179+ - *"Väestö"* tai *"Population"* vasemmalle akselille
180+ - *"Mies/Nais suhde"* tai *"Male-to-female ratio"* oikealle akselille
181+ - *"Ikä (vuosina)"* tai *"Age (Years)"* ala akselille.
182+ - Aseta akselien `LabelFont.Style` arvoon `fsBold`.
183+- Huomaa, että oikean akselin otsikkoa ei kierretty. Akselin `Title.LabelFont` on ominaisuus `Orientation` - tämä kierton kulma ilmoitetaan kymmenesosa asteina. Aseta se arvoon 900 niin saadaan sama suunta kuin vasemman akselin otsikolla.
184+- Pakota oikea akseli **aloittamaan nollasta** asettamalla sen Range.`Range.UseMin` arvoon `true`. Tämä on riittävä, koska `Range.XMin` on 0 oletuksena. Tällä tavalla voit myös valita muita alueita akselille.
185+
186+### Muokataan akselin väliviivojen tekstiä
187+
188+Nyt pitäisi huolehtia siitä, että tulodata on jaettu 1E6 (eli miljoonalla), jotenkin tämä pitäisi osoittaa. Olisi mahdollista muuttaa vasemman akselin otsikkoa "Väestö (miljoonaa)". Mutta mennään eri tavalla nyt: liitetään "M" osoittamaan oikeaan suuruusluokkaa ( "M" = "Mega" = "miljoona") asteikkomerkkeihin. On kaksi tapaa saavuttaa näin: ensimmäinen, on käyttää akselin ominaisuutta `Marks.Format`, jossa "M" voidaan lisätä (% 0: .9g M '). Tai toisella tavoin voimme hyödyntää TChartAxis:n tapahtuman `OnMarkToText`; Tämä tapahtuma mahdollistaa muuttaa asteikkomerkkien tekstiä joka näytetään akselilla. Tässä tapauksessa tehdään seuraavanlainen aliohjelma vasemman akselin tapahtumaan :
189+
190+``` pascal
191+procedure TForm1.Chart1AxisList0MarkToText(var AText: String; AMark: Double);
192+begin
193+ AText := Format('%s M', [AText]);
194+end;
195+```
196+
197+![](/wiki-images/c/cf/TAChart_DualYAxis8.png)
198+
199+### Asetetaan kuvaajien otsikkopalkki (legend)
200+
201+Opetusohjelma on melkein valmis nyt. Mitä on jäljellä on [[TAChart documentation|kuvaajien otsikkopalkki (legend)]] - toistaiseksi ei kerrota käyttäjälle mikä käyrä kuuluu mihinkin tietoihin. Joten, mennään `Chart1.Legend` ominaisuuteen ja asetetaan `Visible` arvoon `true` . Nyt nähdään vain lyhyitä viivoja kuvaajien otsikkopalkkissa (legend), ei tekstejä. Tämä johtuu siitä, ettei ole määritelty `Title`:ä jokaiselle kuvaajalle. Tehdään tämä nyt, kirjoitetaan otsikot *"miehet"* (*"male"*), *"naiset"* (*"female"*) ja *"suhde"*(*"ratio"*) vastaaviin kuvaajiin.
202+
203+![](/wiki-images/c/cb/TAChart_DualYAxis9.png)
204+
205+Koska on kaksi akselia, olisi hienoa saada otsikko "vasen" (*"left"* )miesten ja naisten kuuvaajien yläpuolelle kuvaajien otsikkopalkkiin ja otsikko "oikea" (*"right"*) suhteen kuvaajan yläpuolella. Tämä vaikutus voidaan saavuttaa käyttämällä ryhmiä. Jokaisella kuvaajalla on ominaisuus `Legend` , jota voidaan käyttää ohjaamaan paikkaa kuvaajien otsikkopalkkiin . Ominaisuus `GroupIndex` mahdollistaa kuvaajien ryhmien saamisen yhteisen otsikon alle. Joten, aseta `Legend.GroupIndex` miesten ja naisten kuvaajat nollaan (0) ja aseta suhteen kuvaaja arvoon yksi (1). Sitten mennään `Chart.Legend` ja määrittellään ryhmän otsikot kirjoittamalla tekstiä omaisuutta `Chart.Legend.GroupTitles` ominaisuuteen. Kukin rivi vastaa aina kutakin `GroupIndex` arvoa. Voidaan myös mennä `Chart.Legend.GroupFont` ominaisuuteen ja asettaa fontin lihavoiduksi.
206+
207+Vielä parannettavaa: entäpä jos kuvaajien otsikkopalkki olisi kaavion alla niin, että kuvaajat jotka kuuluvat vasemmalle akselille olisivat vasemmalla ja ne jotka kuuluvat oikealle akselille olisivat oikealla?
208+
209+Aluksi asetamme kuvaajien otsikkopalkin `Alignment` arvoon `laBottomCenter`. Sitten muutamme `ColumnCount` arvoon 2. Olemme onnekkaita - kaikki kuvaajien otsikkopalkin merkinnät mahtuvat menevät aivan kuten haluamme. Muuten täytyisi muokata niiden [[TAChart documentation|Order]] ominaisuutta tai muuttaa omaisuutta `ItemFillOrder` tai ehkä ottaa käyttöön ([[TAChart documentation|tyhjiä kohteita]]).
210+
211+TAChart's kuvaajien otsikkopalkki (legend) on erittäin joustava -- Ole hyvä ja katso sen [[TAChart documentation|dokumentaatio]] saadaksesi lisätietoa siitä.
212+
213+Lopuksi, lisätään teksti *"World population"* kaavion otsikkoon ja referenssi tiedot alatunnisteeseen.
214+
215+![](/wiki-images/4/47/TAChart_DualYAxis11.png)
216+
217+## Lähdekoodi
218+
219+### Project file
220+
221+``` pascal
222+program project1;
223+
224+{$mode objfpc}{$H+}
225+
226+uses
227+ {$IFDEF UNIX}{$IFDEF UseCThreads}
228+ cthreads,
229+ {$ENDIF}{$ENDIF}
230+ Interfaces, // this includes the LCL widgetset
231+ Forms, Unit1, tachartlazaruspkg
232+ { you can add units after this };
233+
234+{$R *.res}
235+
236+begin
237+ RequireDerivedFormResource := True;
238+ Application.Initialize;
239+ Application.CreateForm(TForm1, Form1);
240+ Application.Run;
241+end.
242+```
243+
244+### Unit1.pas
245+
246+``` pascal
247+unit Unit1;
248+
249+{$mode objfpc}{$H+}
250+
251+interface
252+
253+uses
254+ Classes, SysUtils, FileUtil, TAGraph, TASeries, TASources, Forms, Controls,
255+ Graphics, Dialogs, population, TACustomSource, TATransformations, TAChartAxisUtils;
256+
257+type
258+
259+ { TForm1 }
260+
261+ TForm1 = class(TForm)
262+ Chart1: TChart;
263+ LeftAxisTransformations: TChartAxisTransformations;
264+ LeftAxisAutoScaleTransform: TAutoScaleAxisTransform;
265+ RightAxisTransformations: TChartAxisTransformations;
266+ LineSeries_male: TLineSeries;
267+ LineSeries_female: TLineSeries;
268+ LineSeries_ratio: TLineSeries;
269+ ChartSource_male: TUserDefinedChartSource;
270+ ChartSource_female: TUserDefinedChartSource;
271+ ChartSource_ratio: TUserDefinedChartSource;
272+ RightAxisAutoScaleTransform: TAutoScaleAxisTransform;
273+ procedure Chart1AxisList0MarkToText(var AText: String; AMark: Double);
274+ procedure ChartSourceGetChartDataItem(
275+ ASource: TUserDefinedChartSource; AIndex: Integer;
276+ var AItem: TChartDataItem);
277+ procedure FormCreate(Sender: TObject);
278+ private
279+ { private declarations }
280+ PopulationData: TPopulationArray;
281+ public
282+ { public declarations }
283+ end;
284+
285+var
286+ Form1: TForm1;
287+
288+implementation
289+
290+{$R *.lfm}
291+
292+const
293+ POPULATION_FILE = 'population.txt';
294+
295+{ TForm1 }
296+
297+procedure TForm1.ChartSourceGetChartDataItem(
298+ ASource: TUserDefinedChartSource; AIndex: Integer; var AItem: TChartDataItem);
299+begin
300+ AItem.X := PopulationData[AIndex].Age;
301+ if ASource = ChartSource_male then
302+ AItem.Y := PopulationData[AIndex].Male / 1e6
303+ else if ASource = ChartSource_female then
304+ AItem.Y := PopulationData[AIndex].Female / 1e6
305+ else
306+ AItem.Y := PopulationData[AIndex].Ratio / 100;
307+end;
308+
309+procedure TForm1.Chart1AxisList0MarkToText(var AText: String; AMark: Double);
310+begin
311+ AText := Format('%s M', [AText]);
312+end;
313+
314+procedure TForm1.FormCreate(Sender: TObject);
315+begin
316+ LoadPopulationData(POPULATION_FILE, PopulationData);
317+ ChartSource_male.PointsNumber := Length(PopulationData);
318+ ChartSource_female.PointsNumber := Length(PopulationData);
319+ ChartSource_ratio.PointsNumber := Length(PopulationData);
320+end;
321+
322+end.
323+```
324+
325+### Unit1.lfm
326+
327+``` pascal
328+object Form1: TForm1
329+ Left = 365
330+ Height = 409
331+ Top = 169
332+ Width = 470
333+ Caption = 'Form1'
334+ ClientHeight = 409
335+ ClientWidth = 470
336+ OnCreate = FormCreate
337+ LCLVersion = '1.1'
338+ object Chart1: TChart
339+ Left = 0
340+ Height = 409
341+ Top = 0
342+ Width = 470
343+ AxisList = <
344+ item
345+ Grid.Visible = False
346+ Minors = <>
347+ Title.LabelFont.Orientation = 900
348+ Title.LabelFont.Style = [fsBold]
349+ Title.Visible = True
350+ Title.Caption = 'Population'
351+ Transformations = LeftAxisTransformations
352+ OnMarkToText = Chart1AxisList0MarkToText
353+ end
354+ item
355+ Grid.Visible = False
356+ Alignment = calBottom
357+ Minors = <>
358+ Title.LabelFont.Style = [fsBold]
359+ Title.Visible = True
360+ Title.Caption = 'Age (Years)'
361+ end
362+ item
363+ Grid.Visible = False
364+ Alignment = calRight
365+ Minors = <>
366+ Range.UseMin = True
367+ Title.LabelFont.Orientation = 900
368+ Title.LabelFont.Style = [fsBold]
369+ Title.Visible = True
370+ Title.Caption = 'Male-to-female ratio'
371+ Transformations = RightAxisTransformations
372+ end>
373+ BackColor = clWhite
374+ Foot.Alignment = taLeftJustify
375+ Foot.Brush.Color = clBtnFace
376+ Foot.Font.Color = clBlue
377+ Foot.Text.Strings = (
378+ 'Source:'
379+ 'http://www.census.gov/population/international/data/worldpop/tool_population.php'
380+ )
381+ Foot.Visible = True
382+ Legend.Alignment = laBottomCenter
383+ Legend.ColumnCount = 2
384+ Legend.GroupFont.Style = [fsBold]
385+ Legend.GroupTitles.Strings = (
386+ 'left:'
387+ 'right:'
388+ )
389+ Legend.Visible = True
390+ Title.Brush.Color = clBtnFace
391+ Title.Font.Color = clBlue
392+ Title.Font.Style = [fsBold]
393+ Title.Text.Strings = (
394+ 'World population'
395+ )
396+ Title.Visible = True
397+ Align = alClient
398+ ParentColor = False
399+ object LineSeries_male: TLineSeries
400+ Legend.GroupIndex = 0
401+ Title = 'male'
402+ AxisIndexY = 0
403+ LinePen.Color = clSkyBlue
404+ Source = ChartSource_male
405+ end
406+ object LineSeries_female: TLineSeries
407+ Legend.GroupIndex = 0
408+ Title = 'female'
409+ AxisIndexY = 0
410+ LinePen.Color = 16744703
411+ Source = ChartSource_female
412+ end
413+ object LineSeries_ratio: TLineSeries
414+ Legend.GroupIndex = 1
415+ Title = 'ratio'
416+ AxisIndexY = 2
417+ Source = ChartSource_ratio
418+ end
419+ end
420+ object ChartSource_male: TUserDefinedChartSource
421+ OnGetChartDataItem = ChartSourceGetChartDataItem
422+ left = 130
423+ top = 25
424+ end
425+ object ChartSource_female: TUserDefinedChartSource
426+ OnGetChartDataItem = ChartSourceGetChartDataItem
427+ left = 130
428+ top = 79
429+ end
430+ object ChartSource_ratio: TUserDefinedChartSource
431+ OnGetChartDataItem = ChartSourceGetChartDataItem
432+ left = 130
433+ top = 137
434+ end
435+ object LeftAxisTransformations: TChartAxisTransformations
436+ left = 267
437+ top = 25
438+ object LeftAxisAutoScaleTransform: TAutoScaleAxisTransform
439+ end
440+ end
441+ object RightAxisTransformations: TChartAxisTransformations
442+ left = 267
443+ top = 136
444+ object RightAxisAutoScaleTransform: TAutoScaleAxisTransform
445+ end
446+ end
447+end
448+```
449+
450+### population.pas
451+
452+``` pascal
453+unit population;
454+
455+{$mode objfpc}{$H+}
456+
457+interface
458+
459+uses
460+ Classes, SysUtils;
461+
462+type
463+ TPopulationRecord = record
464+ Age: Integer;
465+ Total: Double;
466+ Male: Double;
467+ Female: Double;
468+ Ratio: Double;
469+ end;
470+ TPopulationArray = array of TPopulationRecord;
471+
472+procedure LoadPopulationData(const AFileName: String; var AData: TPopulationArray);
473+
474+implementation
475+
476+procedure LoadPopulationData(const AFileName: String; var AData: TPopulationArray);
477+
478+ function StripThousandSep(const s: String): String;
479+ // Removes the thousand separators from the string
480+ // Otherwise StrToFloat would fail.
481+ var
482+ i: Integer;
483+ begin
484+ Result := s;
485+ for i:=Length(Result) downto 1 do
486+ if Result[i] = ',' then
487+ Delete(Result, i, 1);
488+ end;
489+
490+var
491+ List1, List2: TStringList;
492+ i, j, n: Integer;
493+ s: String;
494+ ds: char;
495+begin
496+ ds := FormatSettings.DecimalSeparator;
497+ List1 := TStringList.Create;
498+ try
499+ List1.LoadFromFile(AFileName);
500+ n := List1.Count;
501+ SetLength(AData, n-2);
502+ FormatSettings.DecimalSeparator := '.';
503+ List2 := TStringList.Create;
504+ try
505+ List2.Delimiter := #9;
506+ List2.StrictDelimiter := true;
507+ j := 0;
508+ for i:=2 to n-1 do begin
509+ List2.DelimitedText := List1[i];
510+ s := List1[i];
511+ with AData[j] do begin
512+ if i < n-1 then
513+ Age := StrToInt(trim(List2[0]))
514+ else
515+ Age := 100; // the last line is "100 +"
516+ Total := StrToFloat(StripThousandSep(trim(List2[1])));
517+ Male := StrToFloat(StripThousandSep(trim(List2[2])));
518+ Female := StrToFloat(StripThousandSep(trim(List2[3])));
519+ Ratio := StrToFloat(trim(List2[4]));
520+ end;
521+ inc(j);
522+ end;
523+ finally
524+ List2.Free;
525+ end;
526+ finally
527+ FormatSettings.DecimalSeparator := ds;
528+ List1.Free;
529+ end;
530+end;
531+
532+end.
533+```
534+
535+---
536+*From the Free Pascal wiki, page "TAChart Tutorial: Dual y axis, Legend/fi", as it stood on 2020-02-29 after a change by Trev, out of the wiki's dump of 2024-05-26. Copyright stays with the author who wrote it, according to the old wiki's [[Licensing]] page. If you have concerns about this material, [message the admin](/wiki-contact).*

Back to history