Skip to content

Commit

Permalink
added the LTOB algorithm
Browse files Browse the repository at this point in the history
  • Loading branch information
haoel committed Sep 6, 2019
1 parent 83041f7 commit 8bcce41
Show file tree
Hide file tree
Showing 4 changed files with 75 additions and 21 deletions.
44 changes: 44 additions & 0 deletions src/downsampling/ltob.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package downsampling

import (
"math"
)

// LTOB down-samples the data to contain only threshold number of points that
// have the same visual shape as the original data
func LTOB(data []Point, threshold int) []Point {

if threshold >= len(data) || threshold == 0 {
return data // Nothing to do
}

sampledData := make([]Point, 0, threshold)

// Bucket size. Leave room for start and end data points
bucketSize := float64(len(data)-2) / float64(threshold-2)

sampledData = append(sampledData, data[0]) // Always add the first point

for bucket := 1; bucket < threshold-1; bucket++ {
startIdx := int(math.Floor(float64(bucket) * bucketSize))
endIdx := int(math.Min(float64(len(data)-1), float64(bucket+1)*bucketSize))

maxArea := -1.0
maxAreaIdx := -1

for i := startIdx; i < endIdx; i++ {
area := calculateTriangleArea(data[i-1], data[i], data[i+1])
if area > maxArea {
maxArea = area
maxAreaIdx = i
}

}

sampledData = append(sampledData, data[maxAreaIdx])
}

sampledData = append(sampledData, data[len(data)-1]) // Always add last

return sampledData
}
18 changes: 9 additions & 9 deletions src/downsampling/lttb.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,12 @@ func LTTB(data []Point, threshold int) []Point {
return data // Nothing to do
}

sampled := make([]Point, 0, threshold)
sampledData := make([]Point, 0, threshold)

// Bucket size. Leave room for start and end data points
bucketSize := float64(len(data)-2) / float64(threshold-2)

sampled = append(sampled, data[0]) // Always add the first point
sampledData = append(sampledData, data[0]) // Always add the first point

// We have 3 pointers represent for
// > bucketLow - the current bucket's beginning location
Expand All @@ -34,8 +34,8 @@ func LTTB(data []Point, threshold int) []Point {
bucketHigh := int(math.Floor(float64(i+2)*bucketSize)) + 1

// Calculate point average for next bucket (containing c)
avgPoint := calculateAverageDataPoint(data[bucketMiddle:bucketHigh+1])
avgPoint := calculateAverageDataPoint(data[bucketMiddle : bucketHigh+1])

// Get the range for current bucket
currBucketStart := bucketLow
currBucketEnd := bucketMiddle
Expand All @@ -51,19 +51,19 @@ func LTTB(data []Point, threshold int) []Point {
area := calculateTriangleArea(pointA, avgPoint, data[currBucketStart])
if area > maxArea {
maxArea = area
maxAreaPoint = currBucketStart
maxAreaPoint = currBucketStart
}
}

sampled = append(sampled, data[maxAreaPoint]) // Pick this point from the bucket
prevMaxAreaPoint = maxAreaPoint // This MaxArea point is the next's prevMAxAreaPoint
sampledData = append(sampledData, data[maxAreaPoint]) // Pick this point from the bucket
prevMaxAreaPoint = maxAreaPoint // This MaxArea point is the next's prevMAxAreaPoint

//move to the next window
bucketLow = bucketMiddle
bucketMiddle = bucketHigh
}

sampled = append(sampled, data[len(data)-1]) // Always add last
sampledData = append(sampledData, data[len(data)-1]) // Always add last

return sampled
return sampledData
}
9 changes: 4 additions & 5 deletions src/downsampling/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,19 @@ import (
"math"
)

func calculateTriangleArea (pa, pb, pc Point) float64 {
area := ((pa.X - pc.X) * (pb.Y - pa.Y) - (pa.X - pb.X) * (pc.Y - pa.Y)) * 0.5
func calculateTriangleArea(pa, pb, pc Point) float64 {
area := ((pa.X-pc.X)*(pb.Y-pa.Y) - (pa.X-pb.X)*(pc.Y-pa.Y)) * 0.5
return math.Abs(area)
}


func calculateAverageDataPoint(points []Point) (avg Point) {

for _ , point := range points {
for _, point := range points {
avg.X += point.X
avg.Y += point.Y
}
l := float64(len(points))
avg.X /= l
avg.Y /= l
return avg
}
}
25 changes: 18 additions & 7 deletions src/main/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,8 @@ func main() {
dataDir := dir + "/../data/"

rawdata := loadPointsFromCSV(dataDir + "source.csv")
samples := downsampling.LTTB(rawdata, 500)
samples_ltob := downsampling.LTOB(rawdata, 500)
samples_lttb := downsampling.LTTB(rawdata, 500)

// Make a line plotter and set its style.
rawLine, err := plotter.NewLine(covertToPlotXY(rawdata))
Expand All @@ -143,15 +144,25 @@ func main() {
//rawLine.LineStyle.Dashes = []vg.Length{vg.Points(5), vg.Points(5)}
rawLine.LineStyle.Color = color.RGBA{R: 255, A: 255}

sampleLine, err := plotter.NewLine(covertToPlotXY(samples))
sampleLine_ltob, err := plotter.NewLine(covertToPlotXY(samples_ltob))
checkError("new line error", err)
sampleLine.LineStyle.Width = vg.Points(1)
sampleLine_ltob.LineStyle.Width = vg.Points(1)
//sampleLine.LineStyle.Dashes = []vg.Length{vg.Points(5), vg.Points(5)}
sampleLine.LineStyle.Color = color.RGBA{B: 255, A: 255}
sampleLine_ltob.LineStyle.Color = color.RGBA{B: 255, A: 255}

sampleLine_lttb, err := plotter.NewLine(covertToPlotXY(samples_lttb))
checkError("new line error", err)
sampleLine_lttb.LineStyle.Width = vg.Points(1)
//sampleLine.LineStyle.Dashes = []vg.Length{vg.Points(5), vg.Points(5)}
sampleLine_lttb.LineStyle.Color = color.RGBA{G: 255, A: 255}

savePNG("Raw Data", "01.png", []string{"Raw Data"}, []*plotter.Line{rawLine})
savePNG("DownSampling Data", "02.png", []string{"DownSampling Data"}, []*plotter.Line{sampleLine})
savePNG("DownSampling Example", "03.png", []string{"Raw", "Sampled"}, []*plotter.Line{rawLine, sampleLine})
savePNG("DownSampling Data - LTOB", "02.png", []string{"DownSampling Data - LTOB"}, []*plotter.Line{sampleLine_ltob})
savePNG("DownSampling Data - LTTB", "03.png", []string{"DownSampling Data - LTTB"}, []*plotter.Line{sampleLine_lttb})

savePNG("DownSampling Example", "05.png",
[]string{"Raw", "Sampled - LTOB", "Sampled - LTTB"},
[]*plotter.Line{rawLine, sampleLine_ltob, sampleLine_lttb})

appendPNGs([]string{"01.png", "02.png", "03.png"}, dataDir+"downsampling.chart.png")
appendPNGs([]string{"01.png", "02.png", "03.png", "05.png"}, dataDir+"downsampling.chart.png")
}

0 comments on commit 8bcce41

Please sign in to comment.