Czasem prosty wykres to za mało aby analizować dane. Kiedy danych jest bardzo dużo musimy udostępnić użytkownikowi możliwość zbliżenia na interesujący go odcinek czasu. Zobaczmy jak to wygląda. Mamy odcinek czasu z notowania waluty euro-usd, kiedy chce wyświetlić wykres tego notowania wszystko jest mało czytelne:
Tutaj jest i tak nieźle ponieważ wykres sam określa minimalne i maksymalne wartości, wasz wykres prawdopodobnie będzie miał minimum w 0 co jeszcze bardziej uniemożliwi jego skuteczną interpretacje. Jak ustawić automatyczne minima i maksima pokaże w tym tutorialu. Zaczynamy od utworzenia nowego projektu. Do projektu dodałem następujące elementy:
Rodzaj elementu | Nazwa elementu | ustawienia |
---|---|---|
Form | Form1 | Name: Form1 Text: Sterowanie wykresem Size: 857; 523 |
Chart | Wykres | Name: Wykres Anchor: Top, Bottom, Left, Right Size: 817; 338 Location: 12; 37 Dodałem jedną serię danych. |
Button | WczytajDane | Text: Wczytaj dane Location: 12; 8 Name: WczytajDane |
Button | lewy1 | Text: << Location: 8; 383 Size: 19; 43 Name: lewy1 Anchor: Bottom, Left |
Button | lewy2 | Text: << Location: 8; 436 Size: 19; 43 Name: lewy2 Anchor: Bottom, Left |
Button | prawy1 | Text: >> Location: 810; 383 Size: 19; 43 Name: prawy1 Anchor: Bottom, Right |
Button | prawy2 | Text: >> Location: 810; 436 Size: 19; 43 Name: prawy2 Anchor: Bottom, Right |
TrackBar1 | TrackBar1 | Location: 33; 381 Size: 771; 45 RightToLeft: No Anchor: Bottom, Left, Right BackColor: White Name: TrackBar1 |
TrackBar2 | TrackBar2 | Location: 33; 432 Size: 771; 45 RightToLeft: No Anchor: Bottom, Left, Right BackColor: White Name: TrackBar2 |
OpenFileDialod | OpenFileDialod1 | Name: OpenFileDialod1 |
Po ustawieniu tych obiektów powinniśmy otrzymać konstrukcję taką jak na obrazku poniżej:
Ja osobiście lubię gdy mój wykres ma specyficzny wygląd jest wtedy według mnie bardziej czytelny, ale wam zostawiam dowolność. Następnym etapem będzie wczytanie danych. Ja lubię gdy dane wczytywane są ze zwykłego pliku *.txt jeśli komuś to nie odpowiada może użyć bazy danych albo przenosić pliki z excela. Wszystkie te możliwości były opisywane na blogu, jeśli ktoś nie wie co i jak niech napisze w komentarzach. Tworzymy uchwyt do naszego przycisku (klikamy go dwukrotnie). Na starcie będziemy potrzebować zmiennej i listy typu double. Kod z opisem prezentuje poniżej:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
Dim kontroler As Boolean = True ' służy do sprawdzania czy lista jest pusta Dim dane As New List(Of Double) Private Sub WczytajDane_Click(sender As Object, e As EventArgs) Handles WczytajDane.Click 'filtr danych OpenFileDialog1.Filter = "csv files|;*.csv;*.txt" OpenFileDialog1.Title = "Select a csv file" OpenFileDialog1.FileName = "" Try With OpenFileDialog1 If .ShowDialog() = DialogResult.OK Then '' kontroler posłuży nam do zaznaczania czy dane są wczytanie czy też nie, '' daje to możliwość załadowania innych danych jeśli te nam już nie będą potrzebna. If kontroler = False Then dane.Clear() 'czyści tablice TworzTabele(.FileName) 'Ładuje dane do listy (nie gotowa na tym etapie) TrackBar2.Value = 0 TrackBar1.Value = 0 tworz_wykres(TrackBar1.Value, TrackBar2.Value) ' funkcja ładująca dane do wykresu (nie gotowa na tym etapie) Else TworzTabele(.FileName) 'Ładuje dane do listy (nie gotowa na tym etapie) tworz_wykres(0, 0) ' funkcja ładująca dane do wykresu (nie gotowa na tym etapie) kontroler = False TrackBar1.Enabled = True TrackBar2.Enabled = True End If End If End With Catch ex As Exception End Try End Sub |
Zajmiemy się teraz funkcją która załaduje nam dane z pliku *.txt do listy o nazwie „dane”. Dodamy możliwość wstawienia separatora, da nam to możliwość importowania list z plików *.CSV . Kod do ładowania danych wygląda następująco:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
Public Sub TworzTabele(ByVal sciezkaDoPliku As String) Dim i As Integer Dim wartosc As String() 'przechowuje dane z pliku Dim f As IO.File = Nothing Dim rodzajkodu As New IO.StreamReader(sciezkaDoPliku, System.Text.Encoding.UTF8) Try Dim k As String k = InputBox("Wprowadź znak separatora. (pozostawienie pustego pola oznacza użycie tabulatora)", "") If k = "" Then wartosc = rodzajkodu.ReadLine().Split(ControlChars.Tab) Else wartosc = rodzajkodu.ReadLine().Split(k) End If For i = 0 To wartosc.Length() - 1 dane.Add(wartosc(i)) Next While rodzajkodu.Peek() <> -1 wartosc = rodzajkodu.ReadLine().Split() For i = 0 To wartosc.Length() - 1 dane.Add(wartosc(i)) 'Ładuje elementy pliku do list dane Next End While Catch ex As Exception MsgBox("Error: " & ex.Message) Finally rodzajkodu.Close() End Try 'ustawia przedział TrackBarów TrackBar1.Maximum = dane.Count - 2 TrackBar2.Maximum = dane.Count - 2 End Sub |
Po załadowaniu danych wystarczy teraz tylko wyświetlić w naszym wykresie. Jak widzicie posłuży nam do tego metoda tworz_wykres. Najpierw musimy importować wymaganą bibliotekę, nad „Public Class” dodajemy linijkę:
1 2 3 |
Imports System.Windows.Forms.DataVisualization.Charting Public Class Form1 |
Kod metody tworz_wykres:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 |
Private Sub tworz_wykres(ByVal wartosc As Integer, ByVal wartosc2 As Integer) ' Określamy minimum i maximum osi y aby nasze dane calościowo mieściły się na wykresie Dim minimum As New Double Dim maximum As New Double 'wstępne ustawienie minimum i maximum minimum = dane(wartosc) maximum = dane(wartosc) 'pętle szukające minimalnych/maxymalnych wartości For i As Integer = wartosc + 1 To dane.Count - 1 - wartosc2 If dane(i) < minimum Then minimum = dane(i) End If Next For i As Integer = wartosc + 1 To dane.Count - 1 - wartosc2 If dane(i) > maximum Then maximum = dane(i) End If Next 'ustawienie wartości Wykres.ChartAreas(0).AxisY.Minimum = Val(minimum) Wykres.ChartAreas(0).AxisY.Maximum = Val(maximum) 'gdy zbliżymu wykres do 20 danych pojawią się znaczniki informujące o wartościach danych If (dane.Count - 3) - wartosc - wartosc2 <= 20 Then Wykres.Series(0).IsValueShownAsLabel = True Wykres.Series(0).LabelFormat = "N4" Wykres.Series(0).MarkerStyle = MarkerStyle.Square Wykres.Series(0).MarkerSize = 5 Else Wykres.Series(0).IsValueShownAsLabel = False Wykres.Series(0).MarkerStyle = MarkerStyle.None End If 'tutaj możemy ustawić właściwości naszego wykresu takie jak rodzaj, nazwę itp Wykres.Series(0).ChartType = DataVisualization.Charting.SeriesChartType.Line Wykres.Series(0).Points.Clear() Wykres.Series(0).Name = "yt" Wykres.Series(0).BorderWidth = 2 'ładuje dane do wykresu For Count As Integer = wartosc To dane.Count - 2 - wartosc2 Wykres.Series(0).Points.AddXY(Count, dane(Count)) Next End Sub |
Wygląda to nieźle według mnie, po załadowaniu znacznej ilości danych mój wykres wygląda tak:
Widzimy ładnie zachowane minima i maxima które pozwalają wypełnić całą przestrzeń wykresu. Jak to bez tych opcji wygląda:
Chyba trochę słabo. Najbardziej widoczne jest to wtedy gdy nasze dane są bardzo małe jak np. dane z rynku FOREX. Wystarczy teraz tylko dodać funkcjonalność Trackbarów i przycisków:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 |
Private Sub TrackBar1_ValueChanged(sender As Object, e As EventArgs) Handles TrackBar1.ValueChanged If (TrackBar1.Value + TrackBar2.Value) < dane.Count - 2 Then tworz_wykres(TrackBar1.Value, TrackBar2.Value) End If End Sub Private Sub TrackBar2_ValueChanged(sender As Object, e As EventArgs) Handles TrackBar2.ValueChanged If (TrackBar1.Value + TrackBar2.Value) < dane.Count - 2 Then tworz_wykres(TrackBar1.Value, TrackBar2.Value) End If End Sub Private Sub lewy1_Click(sender As Object, e As EventArgs) Handles lewy1.Click If (TrackBar1.Value + TrackBar2.Value) < dane.Count - 2 Then If Not TrackBar1.Value = 0 Then TrackBar1.Value -= 1 End If Else End If End Sub Private Sub prawy1_Click(sender As Object, e As EventArgs) Handles prawy1.Click If (TrackBar1.Value + TrackBar2.Value) < dane.Count - 2 Then If Not TrackBar1.Value = dane.Count - 2 Then TrackBar1.Value += 1 End If Else End If End Sub Private Sub Lewy2_Click(sender As Object, e As EventArgs) Handles Lewy2.Click If (TrackBar1.Value + TrackBar2.Value) < dane.Count - 2 Then If Not TrackBar2.Value = dane.Count - 2 Then TrackBar2.Value += 1 End If Else End If End Sub Private Sub prawy2_Click(sender As Object, e As EventArgs) Handles prawy2.Click If (TrackBar1.Value + TrackBar2.Value) < dane.Count - 2 Then If Not TrackBar2.Value = 0 Then TrackBar2.Value -= 1 End If Else End If End Sub |
Po zbliżeniu nasz wykres będzie wyglądał tak:
No i ładnie. Jak zawsze dorzucam pliki do pobrania:
Projekt: Zblizanie_Wykresu
Dane wykorzystane w tutorialu: nowa
Jeśli ktoś jest zainteresowany tylko programem to proszę: Wykres interaktywny
Film prezentujący program :