2013-06-14 17 views
5

Natknąłem się na bibliotekę .Net o nazwie Teafiles.net, która obsługuje przechowywanie i pobieranie szeregów czasowych. Własny produkt, herbaciarnia, może wyznaczać takie szeregi czasowe. Zastanawiam się, czy produkt z herbaciarni jest dostępny również jako kod źródłowy, czy to open source, czy płatna licencja. Interesuje mnie technologia, która umożliwia ładowanie tylko punktów danych, które są widoczne w bieżącym widoku wykresu i jak wdrażać podobne rozwiązanie.Architektura za biblioteką wykresów Teafiles i herbaciarni?

Staram się zaimplementować coś podobnego i zastanawiałem się, czy ktoś nie natknął się na podobną technologię, czy też wie, czy licencjonowana licencja teahouse jest dostępna również z kodem źródłowym.

Odpowiedz

3

Obecnie pracuję nad rozwiązaniem trendów w oparciu o bibliotekę ZedGraph i używam aplikacji TeaFiles do buforowania ogromnej ilości danych pochodzących z bazy danych.

Nie wiem dokładnie, jaka technologia stoi za rozwiązaniem TeaHouse. Ale użyłem również podejścia do wyświetlania zestawu punktów, które są pomiędzy dwoma datami z ogromnej ilości danych pochodzących z TeaFile.

Biblioteka ZedGraph ma obiekt FilteredPointList, który wykonuje automatyczną deklimatyzację punktu danych . Zawiera on metodę SetBounds, która pozwala wybrać zakres dat, które chcesz wyświetlić, oraz maksymalną liczbę punktów, które chcesz wyświetlić. Zwykle odpowiada rzeczywistej szerokości widoku.

Urządzenie FilteredPointList(original source code) wykorzystuje dwie tablice podwójne, które zawierają dane XY. Łatwo jest zaadaptować tę klasę do TeaFilePointList przez zastąpienie tablic przez obiekt TeaFile, biorąc pod uwagę T jako strukturę, która zawiera DateTime i podwójną właściwość.

Implementacja nie jest optymalna, ale zacząłem w ten sposób. Mogę zaktualizować ten kod później, aby uwzględnić funkcję MemoryMappedFile w TeaFile. W ten sposób będzie znacznie szybciej.

public class TeaFilePointList : IPointList 
{ 
    TeaFile<point> tf; 

    private int _maxPts = -1; 
    private int _minBoundIndex = -1; 
    private int _maxBoundIndex = -1; 

    struct point 
    { 
     public TeaTime.Time x; 
     public double y; 
    } 

    public TeaFilePointList(DateTime[] x, double[] y) 
    { 
     tf = TeaFile<point>.Create(Path.GetRandomFileName() + ".tea"); 
     for (var i = 0; i < x.Length; i++) 
      tf.Write(new point() { x = x[i], y = y[i] }); 
    } 

    public void SetBounds(double min, double max, int maxPts) 
    { 
     _maxPts = maxPts; 

     // find the index of the start and end of the bounded range 

     var xmin = (DateTime)new XDate(min); 
     var xmax = (DateTime)new XDate(max); 

     int first = tf.BinarySearch(xmin, item => (DateTime)item.x); 
     int last = tf.BinarySearch(xmax, item => (DateTime)item.x); 

     // Make sure the bounded indices are legitimate 
     // if BinarySearch() doesn't find the value, it returns the bitwise 
     // complement of the index of the 1st element larger than the sought value 

     if (first < 0) 
     { 
      if (first == -1) 
       first = 0; 
      else 
       first = ~(first + 1); 
     } 

     if (last < 0) 
      last = ~last; 

     _minBoundIndex = first; 
     _maxBoundIndex = last; 
    } 

    public int Count 
    { 
     get 
     { 
      int arraySize = (int)tf.Count; 

      // Is the filter active? 
      if (_minBoundIndex >= 0 && _maxBoundIndex >= 0 && _maxPts > 0) 
      { 
       // get the number of points within the filter bounds 
       int boundSize = _maxBoundIndex - _minBoundIndex + 1; 

       // limit the point count to the filter bounds 
       if (boundSize < arraySize) 
        arraySize = boundSize; 

       // limit the point count to the declared max points 
       if (arraySize > _maxPts) 
        arraySize = _maxPts; 
      } 

      return arraySize; 
     } 
    } 

    public PointPair this[int index] 
    { 
     get 
     { 
      if (_minBoundIndex >= 0 && _maxBoundIndex >= 0 && _maxPts >= 0) 
      { 
       // get number of points in bounded range 
       int nPts = _maxBoundIndex - _minBoundIndex + 1; 

       if (nPts > _maxPts) 
       { 
        // if we're skipping points, then calculate the new index 
        index = _minBoundIndex + (int)((double)index * (double)nPts/(double)_maxPts); 
       } 
       else 
       { 
        // otherwise, index is just offset by the start of the bounded range 
        index += _minBoundIndex; 
       } 
      } 

      double xVal, yVal; 
      if (index >= 0 && index < tf.Count) 
       xVal = new XDate(tf.Items[index].x); 
      else 
       xVal = PointPair.Missing; 

      if (index >= 0 && index < tf.Count) 
       yVal = tf.Items[index].y; 
      else 
       yVal = PointPair.Missing; 

      return new PointPair(xVal, yVal, PointPair.Missing, null); 
     } 
    } 

    public object Clone() 
    { 
     throw new NotImplementedException(); // I'm lazy... 
    } 

    public void Close() 
    { 
     tf.Close(); 
     tf.Dispose(); 
     File.Delete(tf.Name); 
    } 
} 

Najtrudniej było wdrożenie BinarySearch dla TeaFile dla szybkiego przeszukiwania rejestru przy użyciu DateTime. Spojrzałem na realizację Array.BinarySearch stosując decompiler i napisałem rozszerzenie poniżej:

public static int BinarySearch<T, U>(this TeaFile<T> tf, U target, Func<T, U> indexer) where T : struct 
{ 
    var lo = 0; 
    var hi = (int)tf.Count - 1; 
    var comp = Comparer<U>.Default; 

    while(lo <= hi) 
    { 
     var median = lo + (hi - lo >> 1); 
     var num = comp.Compare(indexer(tf.Items[median]), target); 
     if (num == 0) 
      return median; 
     if (num < 0) 
      lo = median + 1; 
     else 
      hi = median - 1; 
    } 

    return ~lo; 
} 

Jeśli ZedGraph nie pasuje do Twoich potrzeb, przynajmniej masz pomysł. Algorytm decymacji używany w klasie FilteredPointList jest całkiem niezły i można go dostosować do własnych potrzeb w inny sposób.

+3

Dziękuję Laurent, skończyłem z podobnym rozwiązaniem. Niedostępny kod źródłowy jako część produktu TeaHouse był dla mnie nie do przejścia. Skończyłem z wykorzystaniem mojej własnej struktury plików binarnych i zaadaptowałem ją, by dostarczać profesjonalne rozwiązanie do tworzenia wykresów (SciChart). W ten sposób kontroluję większość kodu źródłowego. –

Powiązane problemy