Sign in Join
Wiki copytemporary

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

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

OldNewLine
11## Johdanto
22
33![](/wiki-images/4/47/TAChart_DualYAxis11.png)
44
55Kun 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.
66
77Kun 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
88
99Tämä on taustana tähän projektiin. Katsotaan väestön tiedot uudelleen, piirretään väkiluku ja mies-nais suhde samaan kaavioon.
1010
1111Opit miten
1212
1313- luoda kaavion, jossa on **kaksi y-akselia**
1414- käyttää automaattista skaalausta akselin asteikko muunnoksessa
1515- tehdään käyttäjän muokkaamia akselin merkintöjä
1616- tehdään kuvaajien otsikkopalkki (legend) käyttämällä vähemmän tunnettuja ominaisuuksia.
1717
1818Kuten 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.
1919
2020## Data
2121
2222Kuten 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
2323
2424``` pascal
2525type
2626 TPopulationRecord = record
2727 Age: Integer;
2828 Total: Double;
2929 Male: Double;
3030 Female: Double;
3131 Ratio: Double;
3232 end;
3333
3434 TPopulationArray = array of TPopulationRecord;
3535```
3636
3737Nyt 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:
3838
3939``` pascal
4040uses
4141 ..., population, ...;
4242
4343type
4444 TForm1 = class(TForm)
4545 // ...
4646 private
4747 PopulationData : TPopulationArray;
4848 // ...
4949 end;
5050
5151const
5252 POPULATION_FILE = 'population.txt';
5353
5454procedure TForm1.FormCreate(Sender: TObject);
5555begin
5656 LoadPopulationData(POPULATION_FILE, PopulationData);
5757end;
5858```
5959
6060## Kaavion valmistelu
6161
6262Nyt voidaan aloittaa kaavion valmistelu...
6363
6464Lisää **`TChart`** komponentti lomakkeelle:
6565
6666- Aseta sen Align ominaisuus arvoon `alClient`.
6767- Aseta sen `BackColor` arvoon `clWhite`.
6868
6969Lisää **kolme viivakuvaajaa** kaavioon:
7070
7171- Vaihda niiden nimet kuvailemmiksi `LineSeries_male`, `LineSeries_female` ja `LineSeries_ratio`.
7272- Aseta `SeriesColor` väri kuvaajalla `LineSeries_male` arvoon `clSkyBlue`, kuvaajalla `LineSeries_female` arvoon `$00FF80FF` ja jätä `LineSeries_ratio` kuvaajan väri mustaksi.
7373
7474Mistä 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.
7575
7676Siksi lisää kolme `TUserDefinedChartSource` -komponenttia lomakkeelle:
7777
7878- Nimetään ne kuvaammaksi `ChartSource_male`, `ChartSource_female` ja `ChartSource_ratio`.
7979- Aseta kunkin chartsource ominaisuus `Source` vastaamaan oikeata viivakuvaajaa.
8080- Kirjoitetaan seuraava tapahtumankäsittelijä ja liitetään se kunkin user-defined chart source:n `OnGetDataItem` tapahtumaan:
8181
8282``` pascal
8383procedure TForm1.ChartSourceGetChartDataItem(
8484 ASource: TUserDefinedChartSource; AIndex: Integer; var AItem: TChartDataItem);
8585begin
8686 AItem.X := PopulationData[AIndex].Age;
8787 if ASource = ChartSource_male then
8888 AItem.Y := PopulationData[AIndex].Male / 1e6
8989 else if ASource = ChartSource_female then
9090 AItem.Y := PopulationData[AIndex].Female / 1e6
9191 else
9292 AItem.Y := PopulationData[AIndex].Ratio / 100;
9393end;
9494```
9595
9696Seuraavaksi 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`.
9797
9898Vä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.
9999
100100Onko 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ä:
101101
102102``` pascal
103103procedure TForm1.FormCreate(Sender: TObject);
104104begin
105105 LoadPopulationData(POPULATION_FILE, PopulationData);
106106 ChartSource_male.PointsNumber := Length(PopulationData);
107107 ChartSource_female.PointsNumber := Length(PopulationData);
108108 ChartSource_ratio.PointsNumber := Length(PopulationData);
109109end;
110110```
111111
112112Tässä vaiheessa lomake ja objekti puu pitäisi näyttää tältä:
113113
114114![](/wiki-images/1/18/TAChart_DualYAxis1.png) ![](/wiki-images/1/1b/TAChart_DualYAxis2.png)
115115
116116ja kun tuon kääntää ja ajaa niin tuloksen pitäisi näyttää joltain tämäntapaiselta:
117117
118118![](/wiki-images/b/bb/TAChart_DualYAxis3.png)
119119
120120Kuten 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.
121121
122122## Asetetaan toinen y-akseli
123123
124124Tarvitaan toinen y-akseli.
125125
126126Tätä varten siirry objektipuuhun, klikkaa hiiren oikealla `AxisList` (oikealla `Chart1`:n alla ) ja lisää uusi akseli kaavioon. Nyt meillä on kolme akselia:
127127
128128![](/wiki-images/c/c4/TAChart_DualYAxis4.png)
129129
130130Valitse akseli \#2, joka on vielä vasen akseli tällä hetkellä ja aseta komponenttimuokkaimessa sen `Alignment` arvoon `calRight`.
131131
132132Tä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.
133133
134134Miten 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ä.
135135
136136Kun tämä käännetään niin tulos on hieman pettymys: ei muutosta - musta suhde-kuvaaja on edelleen hyvin tasainen.
137137
138138![](/wiki-images/b/b4/TAChart_DualYAxis5.png)
139139
140140## Akselin asettaminen automaattisesti muuttuvaan mittakaavaan
141141
142142Syy 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:
143143
144144- [[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.
145145- [[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.
146146- [[TAChart documentation|kuva koordinaatit]] kuuluvat pikseliä ruudulla lasketaan kuvaajan koordinaatteja.
147147
148148Niin, on olemassa kaksi muunnostoimintoa mukana laskettaessa koordinaattien datapisteet näytölle:
149149
1501501. akselin koordinaatit näytön koordinaatteihin käyttäjän määrittelemän `TChartAxisTransform` avulla
1511512. näytön koordinaatit kuvan koordinaateiksi yksinkertaisella lineaarikuvauksen avulla
152152
153153Jos akselin siirtymistä akselista kaavion koordinaatteihin ei ole määritelty niin käytetään yksinkertaista 1: 1 muunnosta.
154154
155155Ai 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.
156156
157157Tätä tarkoitusta varten TAChart on [[TAChart documentation|TAutoScaleAxisTransform]]. Siihen ei ole suoraa pääsyä komponenttipaletilta, mutta sen lapsi löytyy: [[TAChart documentation|TChartAxisTransformations]] -komponentti.
158158
159159Joten, 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` .
160160
161161Tältä näyttää objektipuu näiden käsittelyiden jälkeen:
162162
163163![](/wiki-images/e/ea/TAChart_DualYAxis6.png)
164164
165165Katso `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.
166166
167167Kun käännetään ja ajetaan ohjelma niin silloin nähdään mitä tarkalleen tapahtuu.
168168
169169![](/wiki-images/1/1f/TAChart_DualYAxis7.png)
170170
171171Voisimme 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.
172172
173173## Hieno viilaus
174174
175175Vaikein osa on tehty nyt. Jäljellä on vielä kaavion "heino viilaus".
176176
177177- Poista akseliruudukko (tämä on jo aikaisemmin opetettu). Vasemman ja oikeamman akselin viivat tekevät siitä hyvin sekavan
178178- Lisää **akseleiden otsikot**:
179179 - *"Väestö"* tai *"Population"* vasemmalle akselille
180180 - *"Mies/Nais suhde"* tai *"Male-to-female ratio"* oikealle akselille
181181 - *"Ikä (vuosina)"* tai *"Age (Years)"* ala akselille.
182182 - Aseta akselien `LabelFont.Style` arvoon `fsBold`.
183183- 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.
184184- 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.
185185
186186### Muokataan akselin väliviivojen tekstiä
187187
188188Nyt 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 :
189189
190190``` pascal
191191procedure TForm1.Chart1AxisList0MarkToText(var AText: String; AMark: Double);
192192begin
193193 AText := Format('%s M', [AText]);
194194end;
195195```
196196
197197![](/wiki-images/c/cf/TAChart_DualYAxis8.png)
198198
199199### Asetetaan kuvaajien otsikkopalkki (legend)
200200
201201Opetusohjelma 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.
202202
203203![](/wiki-images/c/cb/TAChart_DualYAxis9.png)
204204
205205Koska 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.
206206
207207Vielä 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?
208208
209209Aluksi 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]]).
210210
211211TAChart's kuvaajien otsikkopalkki (legend) on erittäin joustava -- Ole hyvä ja katso sen [[TAChart documentation|dokumentaatio]] saadaksesi lisätietoa siitä.
212212
213213Lopuksi, lisätään teksti *"World population"* kaavion otsikkoon ja referenssi tiedot alatunnisteeseen.
214214
215215![](/wiki-images/4/47/TAChart_DualYAxis11.png)
216216
217217## Lähdekoodi
218218
219219### Project file
220220
221221``` pascal
222222program project1;
223223
224224{$mode objfpc}{$H+}
225225
226226uses
227227 {$IFDEF UNIX}{$IFDEF UseCThreads}
228228 cthreads,
229229 {$ENDIF}{$ENDIF}
230230 Interfaces, // this includes the LCL widgetset
231231 Forms, Unit1, tachartlazaruspkg
232232 { you can add units after this };
233233
234234{$R *.res}
235235
236236begin
237237 RequireDerivedFormResource := True;
238238 Application.Initialize;
239239 Application.CreateForm(TForm1, Form1);
240240 Application.Run;
241241end.
242242```
243243
244244### Unit1.pas
245245
246246``` pascal
247247unit Unit1;
248248
249249{$mode objfpc}{$H+}
250250
251251interface
252252
253253uses
254254 Classes, SysUtils, FileUtil, TAGraph, TASeries, TASources, Forms, Controls,
255255 Graphics, Dialogs, population, TACustomSource, TATransformations, TAChartAxisUtils;
256256
257257type
258258
259259 { TForm1 }
260260
261261 TForm1 = class(TForm)
262262 Chart1: TChart;
263263 LeftAxisTransformations: TChartAxisTransformations;
264264 LeftAxisAutoScaleTransform: TAutoScaleAxisTransform;
265265 RightAxisTransformations: TChartAxisTransformations;
266266 LineSeries_male: TLineSeries;
267267 LineSeries_female: TLineSeries;
268268 LineSeries_ratio: TLineSeries;
269269 ChartSource_male: TUserDefinedChartSource;
270270 ChartSource_female: TUserDefinedChartSource;
271271 ChartSource_ratio: TUserDefinedChartSource;
272272 RightAxisAutoScaleTransform: TAutoScaleAxisTransform;
273273 procedure Chart1AxisList0MarkToText(var AText: String; AMark: Double);
274274 procedure ChartSourceGetChartDataItem(
275275 ASource: TUserDefinedChartSource; AIndex: Integer;
276276 var AItem: TChartDataItem);
277277 procedure FormCreate(Sender: TObject);
278278 private
279279 { private declarations }
280280 PopulationData: TPopulationArray;
281281 public
282282 { public declarations }
283283 end;
284284
285285var
286286 Form1: TForm1;
287287
288288implementation
289289
290290{$R *.lfm}
291291
292292const
293293 POPULATION_FILE = 'population.txt';
294294
295295{ TForm1 }
296296
297297procedure TForm1.ChartSourceGetChartDataItem(
298298 ASource: TUserDefinedChartSource; AIndex: Integer; var AItem: TChartDataItem);
299299begin
300300 AItem.X := PopulationData[AIndex].Age;
301301 if ASource = ChartSource_male then
302302 AItem.Y := PopulationData[AIndex].Male / 1e6
303303 else if ASource = ChartSource_female then
304304 AItem.Y := PopulationData[AIndex].Female / 1e6
305305 else
306306 AItem.Y := PopulationData[AIndex].Ratio / 100;
307307end;
308308
309309procedure TForm1.Chart1AxisList0MarkToText(var AText: String; AMark: Double);
310310begin
311311 AText := Format('%s M', [AText]);
312312end;
313313
314314procedure TForm1.FormCreate(Sender: TObject);
315315begin
316316 LoadPopulationData(POPULATION_FILE, PopulationData);
317317 ChartSource_male.PointsNumber := Length(PopulationData);
318318 ChartSource_female.PointsNumber := Length(PopulationData);
319319 ChartSource_ratio.PointsNumber := Length(PopulationData);
320320end;
321321
322322end.
323323```
324324
325325### Unit1.lfm
326326
327-``` pascal
327+``` lfm
328328object Form1: TForm1
329329 Left = 365
330330 Height = 409
331331 Top = 169
332332 Width = 470
333333 Caption = 'Form1'
334334 ClientHeight = 409
335335 ClientWidth = 470
336336 OnCreate = FormCreate
337337 LCLVersion = '1.1'
338338 object Chart1: TChart
339339 Left = 0
340340 Height = 409
341341 Top = 0
342342 Width = 470
343343 AxisList = <
344344 item
345345 Grid.Visible = False
346346 Minors = <>
347347 Title.LabelFont.Orientation = 900
348348 Title.LabelFont.Style = [fsBold]
349349 Title.Visible = True
350350 Title.Caption = 'Population'
351351 Transformations = LeftAxisTransformations
352352 OnMarkToText = Chart1AxisList0MarkToText
353353 end
354354 item
355355 Grid.Visible = False
356356 Alignment = calBottom
357357 Minors = <>
358358 Title.LabelFont.Style = [fsBold]
359359 Title.Visible = True
360360 Title.Caption = 'Age (Years)'
361361 end
362362 item
363363 Grid.Visible = False
364364 Alignment = calRight
365365 Minors = <>
366366 Range.UseMin = True
367367 Title.LabelFont.Orientation = 900
368368 Title.LabelFont.Style = [fsBold]
369369 Title.Visible = True
370370 Title.Caption = 'Male-to-female ratio'
371371 Transformations = RightAxisTransformations
372372 end>
373373 BackColor = clWhite
374374 Foot.Alignment = taLeftJustify
375375 Foot.Brush.Color = clBtnFace
376376 Foot.Font.Color = clBlue
377377 Foot.Text.Strings = (
378378 'Source:'
379379 'http://www.census.gov/population/international/data/worldpop/tool_population.php'
380380 )
381381 Foot.Visible = True
382382 Legend.Alignment = laBottomCenter
383383 Legend.ColumnCount = 2
384384 Legend.GroupFont.Style = [fsBold]
385385 Legend.GroupTitles.Strings = (
386386 'left:'
387387 'right:'
388388 )
389389 Legend.Visible = True
390390 Title.Brush.Color = clBtnFace
391391 Title.Font.Color = clBlue
392392 Title.Font.Style = [fsBold]
393393 Title.Text.Strings = (
394394 'World population'
395395 )
396396 Title.Visible = True
397397 Align = alClient
398398 ParentColor = False
399399 object LineSeries_male: TLineSeries
400400 Legend.GroupIndex = 0
401401 Title = 'male'
402402 AxisIndexY = 0
403403 LinePen.Color = clSkyBlue
404404 Source = ChartSource_male
405405 end
406406 object LineSeries_female: TLineSeries
407407 Legend.GroupIndex = 0
408408 Title = 'female'
409409 AxisIndexY = 0
410410 LinePen.Color = 16744703
411411 Source = ChartSource_female
412412 end
413413 object LineSeries_ratio: TLineSeries
414414 Legend.GroupIndex = 1
415415 Title = 'ratio'
416416 AxisIndexY = 2
417417 Source = ChartSource_ratio
418418 end
419419 end
420420 object ChartSource_male: TUserDefinedChartSource
421421 OnGetChartDataItem = ChartSourceGetChartDataItem
422422 left = 130
423423 top = 25
424424 end
425425 object ChartSource_female: TUserDefinedChartSource
426426 OnGetChartDataItem = ChartSourceGetChartDataItem
427427 left = 130
428428 top = 79
429429 end
430430 object ChartSource_ratio: TUserDefinedChartSource
431431 OnGetChartDataItem = ChartSourceGetChartDataItem
432432 left = 130
433433 top = 137
434434 end
435435 object LeftAxisTransformations: TChartAxisTransformations
436436 left = 267
437437 top = 25
438438 object LeftAxisAutoScaleTransform: TAutoScaleAxisTransform
439439 end
440440 end
441441 object RightAxisTransformations: TChartAxisTransformations
442442 left = 267
443443 top = 136
444444 object RightAxisAutoScaleTransform: TAutoScaleAxisTransform
445445 end
446446 end
447447end
448448```
449449
450450### population.pas
451451
452452``` pascal
453453unit population;
454454
455455{$mode objfpc}{$H+}
456456
457457interface
458458
459459uses
460460 Classes, SysUtils;
461461
462462type
463463 TPopulationRecord = record
464464 Age: Integer;
465465 Total: Double;
466466 Male: Double;
467467 Female: Double;
468468 Ratio: Double;
469469 end;
470470 TPopulationArray = array of TPopulationRecord;
471471
472472procedure LoadPopulationData(const AFileName: String; var AData: TPopulationArray);
473473
474474implementation
475475
476476procedure LoadPopulationData(const AFileName: String; var AData: TPopulationArray);
477477
478478 function StripThousandSep(const s: String): String;
479479 // Removes the thousand separators from the string
480480 // Otherwise StrToFloat would fail.
481481 var
482482 i: Integer;
483483 begin
484484 Result := s;
485485 for i:=Length(Result) downto 1 do
486486 if Result[i] = ',' then
487487 Delete(Result, i, 1);
488488 end;
489489
490490var
491491 List1, List2: TStringList;
492492 i, j, n: Integer;
493493 s: String;
494494 ds: char;
495495begin
496496 ds := FormatSettings.DecimalSeparator;
497497 List1 := TStringList.Create;
498498 try
499499 List1.LoadFromFile(AFileName);
500500 n := List1.Count;
501501 SetLength(AData, n-2);
502502 FormatSettings.DecimalSeparator := '.';
503503 List2 := TStringList.Create;
504504 try
505505 List2.Delimiter := #9;
506506 List2.StrictDelimiter := true;
507507 j := 0;
508508 for i:=2 to n-1 do begin
509509 List2.DelimitedText := List1[i];
510510 s := List1[i];
511511 with AData[j] do begin
512512 if i < n-1 then
513513 Age := StrToInt(trim(List2[0]))
514514 else
515515 Age := 100; // the last line is "100 +"
516516 Total := StrToFloat(StripThousandSep(trim(List2[1])));
517517 Male := StrToFloat(StripThousandSep(trim(List2[2])));
518518 Female := StrToFloat(StripThousandSep(trim(List2[3])));
519519 Ratio := StrToFloat(trim(List2[4]));
520520 end;
521521 inc(j);
522522 end;
523523 finally
524524 List2.Free;
525525 end;
526526 finally
527527 FormatSettings.DecimalSeparator := ds;
528528 List1.Free;
529529 end;
530530end;
531531
532532end.
533533```
534534
535535---
536536*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