2009-12-01 32 views
1

我正在使用新的WPF工具包的Chart來繪製大型數據集。我還有一個十字線跟蹤器,它跟蹤鼠標,當它在圖表區域上時,確切地告訴最近的數據點的值(請參閱雅虎財務圖表)。數據過濾或更好的LINQ查詢?

我使用下面的代碼來找到距鼠標當前懸停位置較近(或相等)的最近數據點(關於圖表的令人討厭的細節是它實際上插入了數據以告訴您什麼是EXACT值在那裏你在掀掉你的鼠標,即使該鼠標所在的數據點之間):

TimeDataPoint point = mainSeries.Find(
    new Predicate<TimeDataPoint>(
    delegate(TimeDataPoint p) { 
     return xValue > p.Date && !mainSeries.Exists(new Predicate<TimeDataPoint>(
      delegate(TimeDataPoint middlePoint) { 
       return middlePoint.Date > p.Date && xValue > middlePoint.Date; 
      })); 
    })); 

[這裏,mainSeries簡直就是一個List<TimeDataPoint>]

這非常適用於相對較小的數據集,但一旦我達到12000+點(這將會迅速增加),上面的代碼會減慢n停頓(它通過數據運行12000 +^2次)。

我不擅長構建查詢,所以我想知道是否可以使用更好的LINQ查詢來做到這一點。

編輯:另一個靈感來自@Randolpho評論的想法是這樣的:我將搜索所有低於給定的點(這將是至多n(這裏:12,000+)),然後選擇一個最大值<> (它也應該至多是O(n))。這應該產生相同的結果,但只有在n次操作的順序,因此應該至少更快一點...

我的另一種選擇是實際篩選數據集並保持點數的上限取決於用戶希望看到的細節水平。如果有更高效的查詢的可能性,我寧願不走這條路。

回答

0

根據顯示/圖表的已知分辨率預先計算最近的數據點。然後,當您將鼠標懸停在某個點上時,它將根據已知的預計算值對x/y座標進行簡單查找。

由於性能方面的原因,請在單獨的線程中進行預先計算,並且在計算完成之前不允許顯示這些值。每次更改圖表的大小時重新計算。

底線:沒有任何LINQ查詢可以幫助您在每次對大型數據集進行鼠標懸停時執行該查詢。這是不能做到的。無論如何,你都在看N + 2的訂單。所以預先計算並緩存它,所以你只做一次計算。

這是一個有趣的想法,但是我不需要在12000對以上的對x/y進行查找嗎?您能否詳細說明我應該如何存儲預先計算的x/y對以進行快速查找?例如,我有(200,300)和(250,300)的數據點,用戶的鼠標位於(225,300)。 - 亞歷山德拉

嗯,我想這將取決於圖。根據您的代碼以及您提及的Yahoo Finance Charts,我假設您的數據僅因水平位置而異,即對於給定的X值,您正在計算顯示數據。

在這種情況下,您可以將一個簡單的Dictionary<int, TimeDataPoint>作爲緩存。 Key是經過變換的X座標(即在您的顯示圖形的座標空間中),Value是預先計算的TimeDataPoint。該字典會爲您的顯示圖表中的每個X座標記錄一個記錄,因此400像素寬度的圖表具有400個預先計算的數據點。

如果您的數據針對兩個軸都不同,您可以改爲使用Dictionary<System.Windows.Point, TimeDataPoint>,方法幾乎相同,但這會使字典中的項目數量增加一個數量級。一個400×300的圖表在字典中會有120000個條目,所以權衡是一個更高的內存佔用。

預先計算您的數據是棘手的部分;它必須與你目前的做法有所不同。在這裏我假定xValue是基於X值的日期插值,因爲它與p.Date進行比較。

這可能會實現:

private Dictionary<int, TimeDataPoint> BuildCache(List<TimeDataPoint> mainSeries) 
{ 
    int xPrevious = 0; 
    int xCurrent = 0; 
    Dictionary<int, TimeDataPoint> cache = new Dictionary<int, TimeDataPoint>(); 
    foreach(var p in mainSeries) 
    { 
     xCurrent = XFromDate(p.Date); 
     for(int val = xPrevious; val < xCurrent; val++) 
     { 
      cache.Add(val, p); 
     } 
     xPrevious = xCurrent; 
    } 
    return cache; 
} 

XFromDate將提取特定日期的X座標。我會離開這樣做。 :)

+0

這是一個有趣的想法,但我不需要在12000+對之間查找x/y嗎?您能否詳細說明我應該如何存儲預先計算的x/y對以進行快速查找? 例如,我有(200,300)和(250,300)的數據點,並且用戶的鼠標位於(225,300)。 – Alexandra 2009-12-01 17:24:33