加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

c# – Teafiles和茶馆图表库背后的架构?

发布时间:2020-12-15 05:38:49 所属栏目:百科 来源:网络整理
导读:我遇到了一个名为Teafiles.net的开源.Net库,它处理时间序列的存储和检索.专有产品茶馆可以绘制这样的时间序列.我想知道茶馆产品是否也可以作为源代码,无论是开源还是付费许可.我对能够仅加载当前图表视图中可见的数据点以及如何实现类似解决方案的技术感兴趣
我遇到了一个名为Teafiles.net的开源.Net库,它处理时间序列的存储和检索.专有产品茶馆可以绘制这样的时间序列.我想知道茶馆产品是否也可以作为源代码,无论是开源还是付费许可.我对能够仅加载当前图表视图中可见的数据点以及如何实现类似解决方案的技术感兴趣.

我正在寻找类似的东西,并想知道是否有人遇到过类似的技术,或者知道付费的茶馆许可证是否也有源代码.

解决方法

我目前正在开发基于 ZedGraph库的趋势解决方案,我正在使用TeaFiles来缓存来自数据库的大量数据.

我不确切知道TeaHouse解决方案背后的技术类型.但我也使用了一种方法来显示一组点,这些点位于来自TeaFile的大量数据的两个日期之间.

ZedGraph库有一个FilteredPointList对象,它执行自动数据点抽取.它包含一个SetBounds方法,允许您选择要显示的日期范围以及要显示的最大点数.通常,它对应于视图的实际宽度.

FilteredPointList (original source code)使用两个包含XY数据的double数组.通过使用TeaFile对象替换数组,将此类调整为TeaFilePointList很容易,将T视为包含DateTime和double属性的结构.

实施不是最佳的,但我是这样开始的.我稍后可能会更新此代码以包含TeaFile的MemoryMappedFile功能.这种方式会快得多.

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

最难的部分是为TeaFile实现BinarySearch,使用DateTime快速搜索记录.我使用反编译器查看了Array.BinarySearch实现,并在下面编写了扩展:

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

如果ZedGraph不符合您的需求,至少您明白了. FilteredPointList类中使用的抽取算法非常好,可以通过其他方式进行调整以满足您的需求.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读