# Code elegance and compactness. Help needed with Map, Apply

I need some help with code optimization and compactness.

I have a set of two-dimensional points and I can use the Mathematica function FindClusters to find 4 clusters. I'd like to plot the points together with 4 circles centered at the cluster centroids and with radii equal to the average distance between the points of the cluster and its centroid.

Up to now I've come up with the following code:

data = {{-1.1, 2.6}, {3.9, -0.8}, {4.2, -3.7}, {3.3, 3.5}, {3.9,
5.2}, {4.1, -4.8}, {3.8, 3.7}, {5.6, 0.1}, {3.1, -5.2}, {-0.9,
2.3}, {2.9, 4.1}, {-2.3, 3.9}, {-2.5, 3.}, {2.6, -5.5}, {5.2,
1.9}, {-0.7, 1.3}, {0.9, 2.8}, {-1.5, 3.3}, {3.8,
1.2}, {2.6, -5.1}, {-0.8, 3.2}, {4.7, 0.7}, {3., 3.}, {3.9,
3.6}, {4.5, 1.4}, {4.2, 1.3}, {-1.1, 2.6}, {4.8,
2.4}, {3.3, -3.5}, {3.2, -4.6}, {3.3, -4.9}, {3., 3.5}, {0.7,
2.1}, {3.2, -4.3}, {-2., 0.5}, {-1.2, 2.}, {-1.6, 1.8}, {-3.5,
3.7}, {4.8, 0.2}, {3.3, 2.4}, {-0.1, 2.1}, {-1.3, 2.5}, {4.4,
3.9}, {3.5, 0.2}, {0.1, 2.9}, {-1., 1.6}, {-1.4, 4.5}, {3.2,
2.5}, {-1.6,
2.4}, {2.6, -5.1}, {-3.4, -2.5}, {-3.6, -2.4}, {-3.7, -3.0}, \
{-3.26, -3.8}, {-3.8, -2.8}, {-3.5, -3.3}};
clusterdata =
FindClusters[data, 4,
Method -> {"Agglomerate", "Linkage" -> "Complete"}];
centroids = Mean /@ clusterdata;
Mean[Map[Norm,
clusterdata[[j]] -
Table[Map[Mean, clusterdata][[j]], {Length[
clusterdata[[j]]]}]]], {j, 1, Length[clusterdata]}];
ListPlot[clusterdata, PlotRange -> {{-6, 6}, {-6, 6}},
AspectRatio -> 1, PlotStyle -> PointSize[0.03],
Epilog ->
Table[Circle[#1, #2] &[centroids[[k]], radii[[k]]], {k, 1, Length[clusterdata]}]]


It works, but I'm positive that the same output (starting from, say, the clusterdata list) could be gotten with a much simpler, compact and elegant code and with the wise use of the Map and Apply functions, that are not very easy to control and manage for an occasional Mathematica user like me.

My question is not only about "elegance" but it's also motivated by the fact that this snippet of code must be very much optimized since, in the project I'm working on, the plot must be dynamically updated with around 100 fast moving points.

rF1 = Mean[Norm /@ Standardize[#, Mean, 1 &]] &;
rF2 = Function[{x}, Mean[Norm[# - Mean[x]] & /@ x]];

(* True *)

ListPlot[clusterdata, AspectRatio -> 1, PlotRange -> {{-6, 6}, {-6, 6}},
PlotStyle -> PointSize[0.03],  Epilog -> circles]


You can also use Graphics:

points = {#, Point@#2} & @@@ MapIndexed[{ColorData[1, "ColorList"][[#2[[1]]]], #} &, clusterdata];
pr = Round@Through@{Min, Max}@clusterdata;

Graphics[{PointSize[.03], circles, points}, PlotRange -> {pr, pr}, Axes -> True]


clusterdata = FindClusters[data, 4, Method -> {"Agglomerate", "Linkage" -> "Complete"}];
ListPlot[clusterdata, AspectRatio -> 1, PlotRange -> {{-6, 6}, {-6, 6}}, PlotStyle -> PointSize[0.03],
Epilog -> MapThread[Circle, {Mean /@ clusterdata, 1/Sqrt[2] Norm /@ Variance /@ clusterdata}]]

• Even simpler: Epilog -> MapThread[Circle, {centroids, radii}] Jan 15, 2015 at 17:29
• Actually "1/Sqrt[2] Norm /@ Variance /@ clusterdata" doesn't give the mean distance to the cluster centroid as I intended, whilst kguler's function Function[{x}, Mean[Norm[# - Mean[x]] & /@ x]]; produces exactly what I intended... Jan 21, 2015 at 13:42