EKB Every once in a while I get a data table with gaps, something like this:
10 | 20 | 30 | 40 | 50 | 60 | |
---|---|---|---|---|---|---|
Item 1 | 3.2 | 4.7 | 3.7 | |||
Item 2 | 1.9 | 2.0 | 6.8 | |||
Item 3 | 0.0 | 0.5 | 7.8 | 2.2 | 1.3 |
What I want to do is to fill in the table using interpolation. For example, using linear interpolation, applying the routine to the table above should give
10 | 20 | 30 | 40 | 50 | 60 | |
---|---|---|---|---|---|---|
Item 1 | 3.2 | 3.7 | 4.2 | 4.7 | 4.2 | 3.7 |
Item 2 | 1.9 | 2.0 | 3.2 | 4.4 | 5.6 | 6.8 |
Item 3 | 0.0 | 0.5 | 7.8 | 5.0 | 2.2 | 1.3 |
Here is my solution, with a demo at the end. A couple of notes:
## Worker procs proc phi {x xl xu} { expr {(1.0 * $x - $xl)/(1.0 * $xu - $xl)} } proc linear {x xl yl xu yu} { set phi [phi $x $xl $xu] expr {$yl + $phi * ($yu - $yl)} } proc geometric {x xl yl xu yu} { set phi [phi $x $xl $xu] expr {$yl * pow(1.0 * $yu/$yl, $phi)} } proc interpolate {xs ys f} { set ysnew {} set yl [lindex $ys 0] set xl [lindex $xs 0] set yu {} set xu {} set i 0 foreach yi $ys xi $xs { if [string is double -strict $yi] { set yl $yi set xl $xi set yu {} set xu {} lappend ysnew $yi } else { if {$yu == {}} { set i1 [expr {$i + 1}] foreach xj [lrange $xs $i1 end] yj [lrange $ys $i1 end] { if [string is double -strict $yj] { set yu $yj set xu $xj break } } } lappend ysnew [$f $xi $xl $yl $xu $yu] } incr i } set ysnew } ## Demo console show set xs {10 20 30 40 50 60} puts "\t[join $xs \t]" foreach n {"Item 1" "Item 2" "Item 3"} ys { {3.2 {} {} 4.7 5.2 3.7} {1.9 2.0 {} {} {} 6.8} {0.0 0.5 7.8 {} 2.2 1.3} } { puts "$n\t[join [interpolate $xs $ys linear] \t]" }