Try this: First, set the distance threshold.
d = 0.1;
The main function uses Fold
, which, along with its companion FoldList
and MapThread
, is one of the most useful "functional" functions in the language.
test =
Fold[If[EuclideanDistance[Most@#2, Mean[Most /@ Last[#1]]] < d,
Join[Most[#1], {Join[Last[#1], {#2}]}], Join[#1, {{#2}}]] &,
{Take[gazeSeq[1], 2]}, Drop[gazeSeq[1], 2]];
Essentially what this is doing is taking each point sequentially, comparing it to the mean point of the "last" cluster already built. If the Euclidean distance is within some prespecified threshold, then the new point joins that cluster. Otherwise it starts its own cluster. Notice I am stripping out the time value with Most
before calculating the distance - this is important!
You end up with a bunch of clusters and a bunch of relatively disconnected points. (Output is truncated.)
Length /@ test
{84, 4, 9, 4, 3, 260, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 5, 5, 9, 123, 18, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 2, 2, 1, 1, 1, 1, 1, 1, 1, 189, 45, 3, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 2, 5, 2, 2, 67, 141,
2, 2, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
3, 6, 14, 263,... 11, 5, 48, 91, 48}
So you only want the ones that are actually clusters.
clusters = Select[test, Length[#] > 10 &];
Which look like this.
ListPlot[Map[Most, clusters, {-2}], Frame -> True]

It would be pretty straightforward to build this up into a nice function with the distance threshold as a parameter.
There is probably a neat image processing way to do this too, but I'll leave that to Heike.
edit in response to whuber's suggestion
Here is an alternative that captures the idea that speed between points matters as well as distance from the center of the cluster. A new cluster starts if either the point is too far away from the center or if it is too far from the previous point. Notice that I've used a smaller threshold for the pairwise sequential distance test as the distance from the centre.
test2 = Fold[
If[EuclideanDistance[Most@#2, Mean[Most /@ Last[#1]]] < d ||
EuclideanDistance[Most@#2, Most[#1[[-1, -1]]] ] < 0.5 d,
Join[Most[#1], {Join[Last[#1], {#2}]}], Join[#1, {{#2}}]] &,
{Take[gazeSeq[1], 2]}, Drop[gazeSeq[1], 2]];
This version does a bit better on avoiding overlapping fixations that are really a single fixation.
Length /@ test2
{84, 4, 15, 261, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 5, 156, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2,
2, 1, 1, 1, 1, 1, 1, 1, 234, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 2, 5, 2, 2, 208, 2, 2, 1, 1, 1, 2, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 283,... 192}
clusters2 = Select[test2, Length[#] > 10 &];
ListPlot[Map[Most, clusters2, {-2}], Frame -> True]
