TAChart Tutorial: Function Series/fi

From Free Pascal wiki

English (en) suomi (fi)

Johdanto

FuncSeries10.png

Kävitkö läpi aloitusoppaan? Siinä oppaassa oltiin käytetty joitakin matemaattisia funktioita näyttämään TAChart:n peruskäyttöä viivakuvaajan avulla. Viivakuvaaja, ei kuitenkaan ole paras valinta näyttämään matemaattisia funktioita. TFuncSeries (funktiokuvaaja) sopii paljon paremmin tähän tarkoitukseen. Tämä on kuvaaja, joka - ensisilmäyksellä - näyttää tavalliselta viivakuvaajalta. Mutta taustalla, se on täysin erilainen. Se ei saa sen dataa ChartSource:sta, vaan matemaattiselta funktiolta. Aina kun kuvaaja tarvitsee tietoja se kutsuu OnCalculate tapahtumaa, jossa käyttäjä voi siirtää funktion arvoja pyydettyyn x: n arvoon. Tämä säästää muistia, funktion arvoja ei tarvitse varastoida. Mutta ennen kaikkea, se mahdollistaa laskea funktion arvot zoomaus tason ja kaavion koon mukaan, riittävän kapein välein, niin että kuvaajan käyrä on "sileä" suurillakin suurennoksilla.

Valmistautuminen

Aloitetaan uusi projekti tuomalla vakio TChart komponentti lomakkeelle. Käytetään seuraavia asetuksia:

  • Align: alClient
  • BackColor: clWhite
  • BottomAxis: Grid.Color = clSilver, Title.Caption = 'x', Title.Visible = true, Title.LabelFont.Style = fsBold
  • LeftAxis: Grid.Color = clSilver, Title.Caption = 'y', Title.Visible = true, Title.LabelFont.Style = fsBold

Näiden muutosten jälkeen lomake näyttää samantapaiselta kuin vasempi kuva: FuncSeries1.png

Lisätään TFuncSeries

Aluksi piirretään sinifunktio y = sin(x). Tupla-klikkaa kaaviota, muokkaa kuvaajia ikkuna avautuu. Klikkaa "lisää" ja valitse "funktiokuvaaja " alasveto luettelosta. Kaaviossa nyt näytetään viivaa joka lähtee vasemmasta alakulmasta ja menee oikeaan yläkulmään (se esittää funktiokuvaajaa). Muutetaan kuvaajan väri punaiseksi. Funktiokuvaajalla ei ole SeriesColor ominaisuutta, mutta sillä on ominaisuus Pen tähän tarkoitukseen: Aseta Pen.Color arvoon clRed. Seuraavaksi mennään komponenttimuokkaimen "Tapahtumat" välilehdelle ja tuplaklikataan tapahtumaa OnCalculate . Tämä on se metodi, jossa me määrittelemme funktion toiminnan. OnCalculate metodia kutsutaan aina kun kuvaaja tarvitsee y-arvon annetulle x-arvolle:

procedure TForm1.Chart1FuncSeries1Calculate(const AX: Double; out AY: Double);
begin
  AY := sin(AX);
end;

FuncSeries2.png

Kun tämä käännetään nähdään sinifunktio. Mutta se ei koko aalto - koska ei asetettu akseleita, x:n arvot ovat ainoastaan väliltä -1 ja +1, oletuksena tyhjän x-akselin laajuudessa.

Laajuuden asettaminen

X-laajuus

Laajemman akselin alueen saamiseksi on kaksi vaihtoehtoa: voidaan asettaa kuvaajan extent tai kaavion extent. On hienoisia eroja molemmissa tapauksissa yksinkertaisessa kaaviossakin, mutta ne eivät näy ja siksi siitä ei enempää tässä. Mennään komponenttimuokkaimeen, valitaan kuvaajan ominaisuus Extent, asetetaan akseli alkamaan XMin vaikkapa -10 ja loppumaan XMax +10. Aktivoi nämä akselin rajat asettamalla UseXMin ja UseXMax arvoon true. Kun nyt käännetään niin nähdään sinifunktion -10 ja 10 välillä.

FuncSeries3.png

Y -laajuus

Miksi emme leiki toiminnolla hieman jotta nähdään, mitä tapahtuu? Siirry OnCalculate tapahtumaan uudelleen ja moninkertaista sinifunktio kahdella:

procedure TForm1.Chart1FuncSeries1Calculate(const AX: Double; out AY: Double);
begin
  AY := 2*sin(AX);
end;

FuncSeries4.png

Oho - funktiokuvaaja ei automaattisesti päivitä y :n laajuutta! Tämä pätee vanhassa Lasaruksen versiossa 1.0. Nykyään FuncSeries:ssä on ominaisuus ExtentAutoY. Jos se on asetettu arvoon true niin se toimeenpanee automaattisen laskemisen y:n laajuudelle. Huomaa, että ominaisuus pätee vain, jos molemmat Extent.UseXMin ja Extent.UseXMax ovat asetettu arvoon true. Jos käytössä on Lazaruksen vanha versio niin extent pitää asettaa käsin: Valitse kuvaajan Extent uudelleen asettamalla YMin arvoon -2,YMax arvoon 2 ja UseYMin sekä UseYMax arvoon true. Tämä näyttää koko sinikäyrän amplitudilla 2.

FuncSeries5.png

Zoomaus

Nyt tarkastellaan johdannossa mainittua seikkaa että funktiokuvaaja on aina tarkka, vaikka suurennos olisi suuri. Ero nähdään kun piirretään sinifunktion toisen kerran, mutta nyt se tehdään viivakuvaajalla joka piirtää vain ennalta määriteltyihin segmentteihin.

Lisää "viivakuvaaja" kaavioon, aseta sen Pen.Style arvoon psDash ja lisää seuraava koodi lomakkeen onCreate tapahtumakäsittelijään jossa määritellään kuvaajan tiedot:

procedure TForm1.FormCreate(Sender: TObject);
const
  N = 100;
  XMIN = -10;
  XMAX = 10;
var
  i: Integer;
  x: Double;
begin
  for i:=0 to N-1 do begin
    x := XMIN + (XMAX - XMIN) * i / (N-1);
    Chart1LineSeries1.AddXY(x, 2*sin(x));
  end;
end;

Kun ohjelma käännetään ja ajetaan niin punaisen funktiokuvaajan ja mustan viivakuvaajan käyrät ovat päällekkäin, käyrät on vaikea erottaa. Jos zoomaat kaavion: pitäen hiiren vasenta näppäintä alhaalla ja vetämällä pieni suorakulmio lähelle yhtä sinifunktion maksimihuippua ( vedä hiirellä ylhäältä-vasemmalta oikeaan alakulmaan jolloin saadaan zoomaus aikaan). Kun vapautat hiiren näet nyt zoomatun suorakulmion. Jos suurennus on riittävän suuri, näet segmentit viivakuvaajassa, mutta funktiokuvaaja on edelleen tarkka.

FuncSeries5b.png

Mikä on syy, miksi funktiokuvaaja on niin sileä jopa äärimmäisissä suurennuksissa? Tämä johtuu siitä, että funktio on laskettu hyvin pienin välein. Tämä määritellään TFuncSeries ominaisuudessa Step. Tässä oleva numero on näytön pikseleitä ja siksi tasaisuus on riippumaton zoomauksesta. Useimmissa toiminnoissa sen oletusarvo 2 on hyvä kompromissi lähes täydelliseen resoluutioon ja piirtämisen nopeuteen.

Ennen kuin jatketaan, poista viivakuvaaja emme tarvitse sitä enää. Poista myös FormCreate tapahtumankäsittelijä.

Domain exclusions

Piirretään y = tan(x)

Tässä harjoituksessa haluamme piirtää eri funktion, y = tan(x). Voimme helposti mukauttaa se tähän projektiin muuttamalla toiminnon OnCalculate tapahtumakäsittelijää (Huom. pitää lisätä myös math käännösyksikkö uses lausekkeeseen):

procedure TForm1.Chart1FuncSeries1Calculate(const AX: Double; out AY: Double);
begin
  AY := tan(AX);
end;

FuncSeries6.png

Kaavio näyttää hyvältä ensi silmäyksellä, mutta kun muistaa joitakin perusasioita tan funktiosta koulusta huomaa että (melkein) pystyjuovat lähellä ±1.6, ±4.7, ±7.9 eivät ole oikeita. Toimintoa ei ole määritelty näissä paikoissa (tarkalleen (n+1/2)π). Kuvaajaa ei pitäisi olla siellä. Koska funktiokuvaaja ei "tiedä" näistä katkoksista, se piirtää yhteyden viimeisen ja ensimmäisen lasketun pisteen välille ennen ja jälkeen epäjatkuvuuden. TFuncSeries tarjoaa niin sanottua DomainExclusions joka ratkaisee tämän kysymyksen. Nämä ovat kohtia ja alueita, joissa toimintoa ei ole laskettu ja ole piirretty. Tällä hetkellä DomainExclusions eivät näy komponenttimuokkaimessa, vaan se on käytettävä koodin suorituksen aikana kutsumalla menetelmillä AddPoint tai AddRange. .

Tan funktion tapauksessa, lisätään seuraava koodi lomakkeen onCreate tapahtumakäsittelijään jossa otetaan edellä mainitut seikat laskettaessa huomioon :

procedure TForm1.FormCreate(Sender: TObject);
begin
  with Chart1FuncSeries1.DomainExclusions do begin
    AddPoint(pi/2);      AddPoint(-pi/2);
    AddPoint(3*pi/2);    AddPoint(-3*pi/2);
    AddPoint(5*pi/2);    AddPoint(-5*pi/2);
  end;
end;

FuncSeries7.png

Kaavio on nyt täydellinen?

On kuitenkin huomioitava, että koodi FormCreate metodissa on liian erityinen ja on oikea vain kun x-akselin vaihtelevat -10:stä 10:n. Oletetaan käyttäjä voisi loitontaa tai voisi muuttaa akselin rajat jollakin muulla tavalla. Sitten nämä domain poikkeukset ei välttämättä sovi enää. Siksi pitäisi antaa hieman yleisempi menetelmä, ehkä "UpdateDomainExclusions" ja kutsua sitä tarvittaessa. Ensimmäinen ajatus olisi käyttää kaavion OnExtentChanged tapahtumassa. Menemättä yksityiskohtiin, mutta tämä saattaa aiheuttaa riippuvuuksia joissakin olosuhteissa, koska tämä tapahtuma tehdään kaavion piirtämisen jälkeen. Nykyisissä Lazarus versioissa on kuitenkin uudempi tapahtuma OnExtentChanging joka sopii paremmin, koska sitä kutsutaan ennen piirtämistä. Lazaruksen vanhoissa versioissa voi käyttää tapahtuman käsittelijä TChart.OnAfterDrawBackwall vaikka sen nimi ei ole intuitiivinen tähän tarkoitukseen. Ei saa unohtaa kutsua DomainExclusions.Clear välttämään lisäämästä samoja asioita uudestaan ja uudestaan.

procedure TForm1.UpdateDomainExclusions;
var
  ex: TDoubleRect; // unit TAChartUtils.pas
  x: Integer;
begin
  ex := Chart1.CurrentExtent;
  Chart1.DisableRedrawing;
  try
    with Chart1FuncSeries1.DomainExclusions do begin
      Clear;
      for x := Floor(ex.a.x / Pi - 0.5) to Ceil(ex.b.x / Pi + 0.5) do
        AddPoint((x + 0.5) * Pi);
    end;
  finally
    Chart1.EnableRedrawing;
  end;
end;

Piirretään y = ln(x)

Viimeisessä harjoituksessa lisätään toinen funktio y = ln (x). Kaksoisklikkaa kaaviota uudelleen ja muokkaa kuvaajia ikkunassa lisää toinen funktiokuvaaja. Aseta sen väriksi clBlue ja kirjoita seuraava OnCalculate tapahtumakäsittelijä joka kertoo kuvaajalle log funktion piirtämisen:

procedure TForm1.Chart1FuncSeries2Calculate(const AX: Double; out AY: Double);
begin
  AY := ln(AX);
end;

FuncSeries8.png

Mutta kun ohjelma ajetaan se kaatuu, koska se sai liukulukupoikkeuksen! Mistä se tuli? Koska x-akselin alkaa arvosta -10 ja logaritminen funktio voi laskea ainoastaan ​​positiivisia x-arvoja. Mitä tässä tapauksessa voidaan tehdä? Vastaus on domain poikkeukset, jälleen. Kielletään vain funktion laskenta negatiivisillä arvoilla ja kun x = 0. Tämä voidaan saavuttaa lisäämällä välille -INF - 0 kuvaajaan domain poikkeuksia. Metodi AddRange hoitaa myös päätepisteiden välin, joten emme tarvitse mitään erityistä kun x = 0. Muutetaan lomakkeen OnCreate tapahtumakäsittelijä seuraavasti:

procedure TForm1.FormCreate(Sender: TObject);
begin
  with Chart1FuncSeries1.DomainExclusions do begin
    AddPoint(pi/2);      AddPoint(-pi/2);
    AddPoint(3*pi/2);    AddPoint(-3*pi/2);
    AddPoint(5*pi/2);    AddPoint(-5*pi/2);
  end; { ... tai tämän tilalla olisi parempi olla erillinen 
         UpdateDomainExclusions procedure mistä aiemmin mainittiin tekstissä}
  with Chart1FuncSeries2.DomainExclusions do begin
    AddRange(NegInfinity, 0);
  end;
end;

Nyt ohjelma toimii hyvin.

Eräs asia joka pitää mainita, on DomainExclusions ominaisuus Epsilon . Tämä arvo ohjaa etäisyyttä päätepisteen ulkopuolelle välin ja viimeinen piirretään toiminnon kohta. Sen oletusarvo 1e-6 on sopiva useimmissa tapauksissa, mutta voit lisätä sen ääretön-tyypin epäjatkuvuudet (y = tan(x)), tai alentaa sitä mallintaa auki ulkopuolelle välein. Yksi esimerkki Jälkimmäisessä tapauksessa on funktio y = sqrt(x) , jota ei ole määritelty negatiivisia numeroita, mutta on määritelty x = 0 (toisin kuin logaritmifunktiota); Tässä tapauksessa toimialueen ulkopuolelle ei saisi sisältää x = 0 , mutta koska välein DomainExclusions suljetaan aina voit näyttää tässä vaiheessa kaavion asettamalla Epsilon = 0.

FuncSeries9.png

Viimeistely

Legend

Ennen päätämme voimme soveltaa joitakin parannuksia. Älä näytä useita käyriä samassa kaavion ilman kuvaajien otsikkopalkkia (legend), ilman sitä ei olisi mitään keinoa erottaa ne toisistaan. Anna funktion nimi Title ominaisuuteen kummallekin kuvaajalle ja aseta niiden legend ominaisuuden Visible arvoon true.

Lisätään koordinaatti akselit (TConstantLineSeries)

Graafisissa matemaattisissa funktiossa usein akselit risteävät origossa. TAChart on mahdollisuus siirtää akseleita poispäin reunasta ominaisuudella Position. Tässä tapauksessa mennään toisella tavalla:

Avaa muokkaa kuvaajia ikkuna uudelleen ja lisätään kaksi "kiinteä viiva" kuvaajaa . Nämä ovat hyvin yksinkertaisia ​​kuvaajia, joka näyttää yhdensuuntainen koordinaatiston akseleita. Niiden sijainti määritellään ominaisuudessa Position, niiden suunta - vaaka- tai pystysuoraan LineStyle. Ei ole mitään tekemistä sen kanssa Position jonka oletusarvo on 0. Täytyy vain asettaa yhden kuvaajan LineStyle arvoon lsHorizontal ja toisen arvoon lsVertical . TConstantLineSeries kuvaajalla on myös arrow eli nuoli , joka voidaan aktivoida asettamalla Arrow.Visible arvoon true . Kokeile Arrow ominaisuuksia Length, Width ja BaseLength jotta löydät muodon joka on sopiva.

Lopuksi kannattaa laittaa kiinteän viivakuvaajien omaisuus Legend.Visible arvoon false muuten tulee kaksi tunnistamatonta merkintää legend otsikkopalkkiin.

Tässä lopputulos:

FuncSeries10.png

Lähdekoodi

Lähdekoodin lopullinen versio tämän opetusohjelman projektista löytyy TAChart asennuksen kansiosta tutorials/func_series .