Wykres interaktywny

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:

wykres_dostosowującysie

 

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:

Sterowanie_wykresem1

 

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:

    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:

    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ę:

Imports System.Windows.Forms.DataVisualization.Charting

Public Class Form1

Kod metody tworz_wykres:

    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:

Sterowanie_wykresem2

Widzimy ładnie zachowane minima i maxima które pozwalają wypełnić całą przestrzeń wykresu. Jak to bez tych opcji wygląda:

Sterowanie_wykresem3

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:

    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:

Sterowanie_wykresem4

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 :

 

Permalink do tego artykułu: https://visualmonsters.cba.pl/wykres-interaktywny/

Dodaj komentarz

Twój adres email nie będzie publikowany.