RTadeusiewicz.NN.Controls
Do rysowania wykresów służy kontrolka ChartPlotter
. Kontrolka ta potrafi
narysować układ współrzędnych i... właściwie cokolwiek. Sama w sobie rysuje osie
układu współrzędnych.
To, czy kontrolka rysuje osie układu, kontroluje własność AxesVisibility
. Własność
TicksVisibility
pozwala pokazać lub ukryć podziałkę. Własność TicksDistance
określa rozmiar podziałki. Obserwowaną powierzchnię określa własność VisibleSurface
.
Niestety, nie jest ona edytowalna w designerze, trzeba ją ustawiać bezpośrednio
w kodzie.
Dane rysowane na wykresie określane są przez własność DataSeries
. Są to serie danych
(pojęcie analogiczne do serii danych z Excela). Jest to kolekcja
obiektów dziedziczących
po klasie DataSeries
. Każdy z tych obiektów reprezentuje jedną serię danych, aczkolwiek może równie dobrze reprezentować cokolwiek innego, gdyż w całości odpowiada on za rysowanie. Kolor i grubość linii danej serii możemy ustawić własnościami
DataSeries.ForeColor
i DataSeries.LineWidth
.
Przykład użycia tej kontrolki można zobaczyć w projekcie LibraryTest
.
Aby narysować wykres składający się z serii linii (tj. będący łamaną), należy do
kolekcji ChartPlotter.DataSeries
dodać obiekt klasy ListDataSeries
.
Klasa ta zawiera własność Data, która zawiera struktury PointF odpowiadające kolejnym
wierzchołkom łamanej. Oczywiście aby narysować coś sensownego, kolekcja powinna
ta mieć co najmniej 2 elementy.
Inną możliwością jest uzycie obiektu klasy ComputedDataSeries
. Jest on przeznaczony
do rysowania wykresów funkcji, w szczególności funkcji gładkich. Tutaj rysowany
obiekt zadany jest nie serią punktów, lecz funkcją odzwierciedlającą współrzędne
poziome na pionowe. Co istotne, funkcja ta jest obliczana dla każdej
widocznej kolumny ekranu, dzięki czemu dobrze się skaluje, zachowując gładkość nawet
przy zmianie rozmiaru kontrolki macierzystej. Rysowaną funkcję ustawiamy przypisując
do własności Function
delegata typu ComputedDataSeries.DrawableFunction
,
czyli funkcji przyjmującej argument typu double
i zwracającej wartość typu double
.
Jeśli wyświetlana funkcja ma być nie tylko gładka, ale również zależna od jakiegoś
"zewnętrznego" parametru, najlepiej jest się posłużyć "obiektem funkcyjnym". W tym
celu tworzymy klasę naszej funkcji bazującą na ComputedDataSeries.ParametrizedFunction
i przypisujemy obiekt tej klasy do własności ComputedSeries.FunctionObject
. Najlepiej
to zrozumieć na bazie przykładu zawartego w projekcie LibraryTest.
Inną możliwością jest rysowanie wykresów składających się z serii punktów. W tym
celu należy do kolekcji ChartPlotter.DataSeries
dodać obiekt klasy
PointDataSeries
. Zawiera ona kolekcję Points
składającą się ze struktur
typu PointDataSeries.ChartPoint
. Każdy taki element reprezentuje pojedynczy punkt.
Struktura PointDataSeries.ChartPoint
zawiera następujące pola:
Coords
Color
Color.Empty
, oznacza to, że punkt ma być rysowany w kolorze
zgodnym z własnością ForeColor
serii danych.DrawLines
Shape
Wielkość punktów można zmienić własnością PointDataSeries.PointSize
(być może w
przyszłości każdy punkt będzie mógł mieć rozmiar ustalany indywidualnie).
Rysowanie wykresów wizualizujących funkcję dwuargumentową przy pomocy koloru umożliwia
klasa Computed2DSeries
. Jej użycie jest analogiczne do użycia klasy
ComputedDataSeries
. Ma ona własne wewnętrzne typy delegatów i funkcji parametryzowanej.
Aby narysować odpowiedź sieci neuronowej o dwóch wejściach i dowolnej ilości wyjść,
należy użyć klasy NetworkResponseDrawableFunction
. Należy pamiętać
tylko o tym, że kolory, jakimi zabarwiane są poszczególne wyjścia, ustawiamy poprzez
własność OutputColors
. Musi być ich przynajmniej tyle ile wyjść ma sieć.
Kontrolka BorderedControl
to po prostu kontrolka zawierająca ramkę.
Klasa WizardForm
to klasa pozwalająca na tworzenie kreatorów. Jest to formatka zawierająca
przyciski Dalej i Wstecz oraz kontener na panele typu WizardPanel
.
Aby z nich skorzystać, należy utworzyć własną formatkę dziedziczącą z WizardForm
oraz własne panele dziedziczące z WizardPanel
, nadpisując metody GetNext()
i GetPrevious()
oraz własności IsFirst
i IsLast
. Wymienione metody odpowiadają
za utworzenie poprzedniego i następnego panela w reakcji na naciśnięcie odpowiedniego
przycisku kreatora, natomiast własności - za określenie, czy panel jest pierwszy
lub ostatni.
W formie dziedziczącej po WizardForm
wystarczy do własności CurrentPanel
przypisać
panel, jaki ma być wyświetlany na początku.
Należy na razie uważać na zmienianie rozmiaru formatki - trzeba to robić poprzez przypisanie rozmiaru w kodzie; przypisanie rozmiaru w designerze powoduje zrujnowanie układu kontrolek (to nie jest moja wina, lecz samego designera). Na razie nie znam jeszcze metody na przypisanie rozmiaru skalującego się zgodnie z rozdzielczością DPI ekranu użytkownika. Jakieś pomysły?