Add SPIFF correction#799
Conversation
|
@nkeim |
|
Hi! Thanks for this PR!! I’ve seen SPIFF before and I’m glad it could be part of trackpy.
The more “active” maintainers are also faculty, so our attention to trackpy (for non-urgent matters) is somewhat seasonal. I can’t give you a definite timeline, but obviously our activity tends to pick up in late Spring/early summer. We’ll do our best to take a look before then!
Nathan
On Feb 3, 2026, at 2:17 PM, Abel Putnoki ***@***.***> wrote:
[https://avatars.githubusercontent.com/u/29568469?s=20&v=4]putnokiabel left a comment (soft-matter/trackpy#799)<#799 (comment)>
@nkeim<https://github.com/nkeim>
Hi, I'm new here!
Is there a process for contributing to trackpy (other than just submitting a PR and waiting)?
—
Reply to this email directly, view it on GitHub<#799 (comment)>, or unsubscribe<https://github.com/notifications/unsubscribe-auth/AAWY23ISYEZVWVCFIDEAVKL4KDX4HAVCNFSM6AAAAACS6XKRE6VHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZTQNBTGE3TKOBZGE>.
You are receiving this because you were mentioned.Message ID: ***@***.***>
|
nkeim
left a comment
There was a problem hiding this comment.
Looks great! See comments.
I'm open to adding a spiff option to locate and batch. We'd have to be deliberate about the behavior when there aren't enough features.
- Perhaps the values could be True, False, and None (or 'auto')? Only
Truewould raise a warning if there were too few features. - I'd prefer to leave it turned off by default in the next trackpy release. We can add it to the walkthrough to let people experiment with it. But you're right that making it the default in a later release could make sense — the performance penalty is small, and it's (currently) hard to imagine cases where the correction would be unwelcome.
| @@ -0,0 +1,45 @@ | |||
| import unittest | |||
|
|
|||
| from build.lib.trackpy.utils import default_pos_columns | |||
There was a problem hiding this comment.
| from build.lib.trackpy.utils import default_pos_columns | |
| from trackpy.utils import default_pos_columns |
| (SPIFF) algorithm" by Yuval et al. | ||
| The accuracy of this algorithm improves with the number of features. When | ||
| tracking features across multiple frames (e.g. in a video), consider locating | ||
| the features across all features first (using tp.batch) before applying this function |
There was a problem hiding this comment.
| the features across all features first (using tp.batch) before applying this function | |
| the features across all frames first (using tp.batch) before applying this function |
| (as opposed to applying this function for each individual frame). | ||
| If f contains less than 100 features, f is returned as-is, due to lack of data. | ||
| """ | ||
| if len(f) < 100: |
|
I thought of one reason not to make SPIFF automatic: it can mask a poor choice of locate parameters. SPIFF works best when the corrections are small—and it does not correct other data like mass and eccentricity. At least until we think of something better, it's probably best to let users decide when the raw coordinates are good enough, and then apply the correction before linking—and after applying cuts on eccentricity, etc. to remove spurious particles. |
Closes #695. Closes #413.
Feature
Based on https://www.nature.com/articles/s41598-017-14166-6?WT.feed_name=subjects_optical-manipulation-and-tweezers#Sec9 .
Use SPIFF to remove pixel-locking bias and improve sub-pixel accuracy of located features.
In the test cases shown (see
test_spiff.py), you can see an order of magnitude better accuracy when the SPIFF correction is applied.Sample results
Verify by adding the following line in

test_spiff.pyand running the tests:2D
error before: 0.1300
error after SPIFF: 0.01998
3D
error before SPIFF: 0.2486
error after SPIFF: 0.0227
Note on documentation and further integration
I did not invest time into updating the documentation and further integrating it into the basic features yet, as I wanted to see what the maintainers think of the feature first.
Since it seems like SPIFF improves accuracy pretty much universally, I'd suggest the following (but feel free to ignore or suggest something else):
apply_spiffargument intp.locate()andtp.batch()(could be enabled or disabled by default) and have those functions apply the SPIFF correction so the user doesn't have to know or think about it necessarily.apply_spiffargument as well as the underlyingapply_spiff_correctionfunction.apply_spiff_correctionmethod for more details on this).