2013-06-14 10 views
5

Mi sono imbattuto in una libreria .net open source chiamata Teafiles.net che gestisce la memorizzazione e il recupero delle serie temporali. Il prodotto proprietario, casa da tè, può tracciare tali serie temporali. Mi chiedo se il prodotto della casa da tè sia anche disponibile come codice sorgente, sia open source che a pagamento. Sono interessato alla tecnologia alla base della capacità di caricare solo punti dati visibili nella vista corrente del grafico e come implementare una soluzione simile.Architettura dietro la Teafiles e la biblioteca dei grafici delle sale da tè?

Sto cercando di implementare qualcosa di simile e chiedevo se qualcuno ha incontrato una tecnologia simile o sa se la licenza casa da tè a pagamento è disponibile con il codice sorgente anche.

risposta

3

Attualmente sto sviluppando una soluzione di tendenza basata sulla libreria ZedGraph e sto utilizzando TeaFiles per memorizzare una quantità enorme di dati provenienti da un database.

Non so esattamente che tipo di tecnologia sta dietro la soluzione sala da tè. Ma ho anche usato un approccio per visualizzare un insieme di punti che sono tra due date da un'enorme quantità di dati provenienti da TeaFile.

La libreria ZedGraph ha un oggetto FilteredPointList che esegue una decimazione automatica del punto di dati . Include un metodo SetBounds che consente di scegliere l'intervallo di date che si desidera visualizzare e la quantità massima di punti che si desidera mostrare. Normalmente, corrisponde alla larghezza effettiva della tua vista.

Il FilteredPointList(original source code) utilizza due matrici di doppio che contengono i dati XY. È facile adattare questa classe a TeaFilePointList sostituendo gli array con un oggetto TeaFile, considerando T come una struttura che contiene un DateTime e una doppia proprietà.

L'implementazione non è ottimale, ma ho iniziato in questo modo. Potrei aggiornare questo codice in seguito per includere la funzione MemoryMappedFile di TeaFile. Sarà molto più veloce in questo modo.

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); 
    } 
} 

La parte più difficile è stato quello di implementare un BinarySearch per TeaFile per quick-la ricerca di un record utilizzando un DateTime. Ho guardato l'attuazione Array.BinarySearch utilizzando un decompilatore, e ho scritto l'estensione di seguito:

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; 
} 

Se ZedGraph non si adatta alle tue esigenze, almeno hai avuto l'idea. L'algoritmo di decimazione utilizzato nella classe FilteredPointList è abbastanza buono e può essere adattato alle tue esigenze in un altro modo.

+3

Grazie Laurent, ho finito con soluzione simile. Il non disponibile del codice sorgente come parte del prodotto TeaHouse era un no-go per me. Ho finito per utilizzare la mia struttura di file binari e adattato per alimentare una soluzione di creazione di grafici professionale (SciChart). In questo modo ho il controllo della maggior parte del codice sorgente. –

Problemi correlati