You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Can you make virtualisation possible in order to accelerate speed for large amount of points.
Currently I am adding/removing points from series as I scroll to position. With option I have set how many points I can show on the chart.
I have 3 collections of points in the background - raw points, processed points and displayed points. Displayed points are linked to series values. All points are in observable collection and are updated.
Bottlenecks are determining how many points are displayed. I'll have to sort this out and make a proper algorithm since I don't have to scan whole collection to get visible count.
Also note that chart series dissapears on helper chart for no reason after setting updates series (new collection set to series). I tried update, refresh etc... nothing works. Only if I move something on the chart on X direction.
Private Function DownsampleWithMinMax(Of T)(points As List(Of T), maxPoints As Integer) As List(Of T)
If points Is Nothing OrElse points.Count = 0 Then Return New List(Of T)
If maxPoints <= 0 OrElse points.Count <= maxPoints Then Return New List(Of T)(points)
' Each bucket adds 4 points: open, high, low, close
Dim bucketCount As Integer = Math.Max(1, maxPoints \ 4)
Dim bucketSize As Integer = Math.Max(1, points.Count \ bucketCount)
Dim result As New List(Of T)(bucketCount * 4)
Dim getYMin As Func(Of T, Double)
Dim getYMax As Func(Of T, Double)
Dim getX As Func(Of T, Long)
If GetType(T) Is GetType(FinancialPoint) Then
getYMin = Function(p) DirectCast(CObj(p), FinancialPoint).Low
getYMax = Function(p) DirectCast(CObj(p), FinancialPoint).High
getX = Function(p) DirectCast(CObj(p), FinancialPoint).Date.Ticks
ElseIf GetType(T) Is GetType(DateTimePoint) Then
getYMin = Function(p) DirectCast(CObj(p), DateTimePoint).Value
getYMax = getYMin
getX = Function(p) DirectCast(CObj(p), DateTimePoint).DateTime.Ticks
ElseIf GetType(T) Is GetType(ObservablePoint) Then
getYMin = Function(p) DirectCast(CObj(p), ObservablePoint).Y
getYMax = getYMin
getX = Function(p) CLng(DirectCast(CObj(p), ObservablePoint).X)
ElseIf GetType(T) Is GetType(LogPoint) Then
getYMin = Function(p) DirectCast(CObj(p), LogPoint).Y
getYMax = getYMin
getX = Function(p) CLng(DirectCast(CObj(p), LogPoint).X)
ElseIf GetType(T) Is GetType(ObservableValue) Then
getYMin = Function(p) DirectCast(CObj(p), ObservableValue).Value
getYMax = getYMin
getX = Function(p) CLng(DirectCast(CObj(p), ObservableValue).Coordinate.SecondaryValue)
ElseIf GetType(T) Is GetType(FinancialPointI) Then
getYMin = Function(p) DirectCast(CObj(p), FinancialPointI).Low
getYMax = Function(p) DirectCast(CObj(p), FinancialPointI).High
getX = Function(p) CLng(DirectCast(CObj(p), FinancialPointI).Coordinate.SecondaryValue)
Else
Throw New InvalidOperationException("Unsupported point type: " & GetType(T).Name)
End If
Dim i As Integer = 0
While i < points.Count
Dim openPoint As T = points(i)
Dim closePoint As T = points(Math.Min(i + bucketSize - 1, points.Count - 1))
Dim minPoint As T = openPoint
Dim maxPoint As T = openPoint
Dim minVal As Double = getYMin(openPoint)
Dim maxVal As Double = getYMax(openPoint)
Dim jEnd As Integer = Math.Min(i + bucketSize, points.Count)
For j As Integer = i + 1 To jEnd - 1
Dim p As T = points(j)
Dim yLow As Double = getYMin(p)
Dim yHigh As Double = getYMax(p)
If yLow < minVal Then
minVal = yLow
minPoint = p
End If
If yHigh > maxVal Then
maxVal = yHigh
maxPoint = p
End If
Next
' Add points in chronological order
Dim ordered = New List(Of T) From {openPoint, minPoint, maxPoint, closePoint}
ordered.Sort(Function(a, b) getX(a).CompareTo(getX(b)))
result.AddRange(ordered)
i += bucketSize
End While
Return result
End Function
Function DownsampleByFactorMinMax(Of T)(points As IEnumerable(Of T), factor As Integer) As ObservableCollection(Of T)
If points Is Nothing OrElse points.Count = 0 OrElse factor <= 1 Then Return points
Dim batchSize As Integer = factor * 2
Dim count As Integer = points.Count
Dim result As New ObservableCollection(Of T)
' Fast delegates for Y, X, and clone/update (to keep original type)
Dim getY As Func(Of T, Double)
Dim getX As Func(Of T, Long)
Dim clonePoint As Func(Of T, T, T, T) = Nothing ' Only for Financial points
If GetType(T) Is GetType(FinancialPoint) Then
getY = Function(p) DirectCast(CObj(p), FinancialPoint).High ' We'll track High and Low separately
getX = Function(p) DirectCast(CObj(p), FinancialPoint).Date.Ticks
clonePoint = Function(firstP, minP, maxP)
Dim fpFirst = DirectCast(CObj(firstP), FinancialPoint)
Dim fpMin = DirectCast(CObj(minP), FinancialPoint)
Dim fpMax = DirectCast(CObj(maxP), FinancialPoint)
Dim fpLast = DirectCast(CObj(maxP), FinancialPoint)
Return DirectCast(CObj(New FinancialPoint With {
.Date = fpFirst.Date,
.Open = fpFirst.Open,
.High = fpMax.High,
.Low = fpMin.Low,
.Close = fpLast.Close
}), T)
End Function
ElseIf GetType(T) Is GetType(FinancialPointI) Then
getY = Function(p) DirectCast(CObj(p), FinancialPointI).High
getX = Function(p) CLng(DirectCast(CObj(p), FinancialPointI).Coordinate.SecondaryValue)
clonePoint = Function(firstP, minP, maxP)
Dim fpFirst = DirectCast(CObj(firstP), FinancialPointI)
Dim fpMin = DirectCast(CObj(minP), FinancialPointI)
Dim fpMax = DirectCast(CObj(maxP), FinancialPointI)
Dim fpLast = DirectCast(CObj(maxP), FinancialPointI)
Return DirectCast(CObj(New FinancialPointI With {
.Coordinate = fpFirst.Coordinate,
.Open = fpFirst.Open,
.High = fpMax.High,
.Low = fpMin.Low,
.Close = fpLast.Close
}), T)
End Function
ElseIf GetType(T) Is GetType(DateTimePoint) Then
getY = Function(p) DirectCast(CObj(p), DateTimePoint).Value
getX = Function(p) DirectCast(CObj(p), DateTimePoint).DateTime.Ticks
ElseIf GetType(T) Is GetType(ObservablePoint) Then
getY = Function(p) DirectCast(CObj(p), ObservablePoint).Y
getX = Function(p) CLng(DirectCast(CObj(p), ObservablePoint).X)
ElseIf GetType(T) Is GetType(LogPoint) Then
getY = Function(p) DirectCast(CObj(p), LogPoint).Y
getX = Function(p) CLng(DirectCast(CObj(p), LogPoint).X)
ElseIf GetType(T) Is GetType(ObservableValue) Then
getY = Function(p) DirectCast(CObj(p), ObservableValue).Value
getX = Function(p) CLng(DirectCast(CObj(p), ObservableValue).Coordinate.SecondaryValue)
Else
Throw New InvalidOperationException("Unsupported point type: " & GetType(T).Name)
End If
Dim i As Integer = 0
While i < count
Dim batchEnd As Integer = Math.Min(i + batchSize, count)
Dim minIndex As Integer = i
Dim maxIndex As Integer = i
Dim minY As Double = getY(points(i))
Dim maxY As Double = minY
' Find min and max Y in this batch
For j As Integer = i To batchEnd - 1
Dim y = getY(points(j))
If y < minY Then
minY = y
minIndex = j
ElseIf y > maxY Then
maxY = y
maxIndex = j
End If
Next
Dim pMin = points(minIndex)
Dim pMax = points(maxIndex)
' Keep chronological order
If getX(pMin) < getX(pMax) Then
result.Add(pMin)
result.Add(pMax)
Else
result.Add(pMax)
result.Add(pMin)
End If
i += batchSize
End While
Return result
End Function
Function DownsampleCandlestickToPoints(Of T)(
candleSeries As IEnumerable(Of FinancialPoint),
maxPoints As Integer,
selector As Func(Of FinancialPoint, Double),
pointFactory As Func(Of DateTime, Double, T)
) As List(Of T)
If candleSeries Is Nothing OrElse Not candleSeries.Any() Then Return New List(Of T)
If maxPoints <= 0 OrElse candleSeries.Count() <= maxPoints Then Return candleSeries.Select(Function(p) pointFactory(p.Date, selector(p))).ToList()
Dim bucketSize = Math.Max(1, Math.Floor(candleSeries.Count() / maxPoints))
Dim result As New List(Of T)
For i = 0 To candleSeries.Count() - 1 Step bucketSize
Dim bucket = candleSeries.Skip(i).Take(bucketSize).ToList()
If bucket.Count = 0 Then Continue For
Dim avgValue = bucket.Average(selector)
Dim midTime = bucket(bucket.Count \ 2).Date
result.Add(pointFactory(midTime, avgValue))
Next
Return result
End Function
Function DownsampleCandlestickToObservableValues(
candleSeries As IEnumerable(Of FinancialPointI),
maxPoints As Integer,
selector As Func(Of FinancialPointI, Double)
) As List(Of ObservableValue)
Dim result As New List(Of ObservableValue)
If candleSeries Is Nothing OrElse Not candleSeries.Any() Then Return result
Dim total = candleSeries.Count()
If maxPoints <= 0 OrElse total <= maxPoints Then
Return candleSeries.Select(Function(p) New ObservableValue(selector(p))).ToList()
End If
Dim bucketSize = Math.Max(1, Math.Floor(total / maxPoints))
For i = 0 To total - 1 Step bucketSize
Dim bucket = candleSeries.Skip(i).Take(bucketSize).ToList()
If bucket.Count = 0 Then Continue For
Dim avgValue = bucket.Average(selector)
result.Add(New ObservableValue(avgValue))
Next
Return result
End Function
reacted with thumbs up emoji reacted with thumbs down emoji reacted with laugh emoji reacted with hooray emoji reacted with confused emoji reacted with heart emoji reacted with rocket emoji reacted with eyes emoji
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
-
Can you make virtualisation possible in order to accelerate speed for large amount of points.
Currently I am adding/removing points from series as I scroll to position. With option I have set how many points I can show on the chart.
I have 3 collections of points in the background - raw points, processed points and displayed points. Displayed points are linked to series values. All points are in observable collection and are updated.
Bottlenecks are determining how many points are displayed. I'll have to sort this out and make a proper algorithm since I don't have to scan whole collection to get visible count.
Also note that chart series dissapears on helper chart for no reason after setting updates series (new collection set to series). I tried update, refresh etc... nothing works. Only if I move something on the chart on X direction.
https://youtu.be/CKK2RSVnKtE
For other I can share downsample methods.
Beta Was this translation helpful? Give feedback.
All reactions