Generating a convex hull with the hull boundary points labeled
SeedRandom[1]
data = Transpose[{RandomReal[1, {10, 2}], RandomInteger[100, 10]}];
xy = data[[All,1]];
labels = data[[All,2]];
rule = Thread[xy -> labels];
ConvexHullMesh[xy, Prolog -> Point[xy], Frame -> True,
MeshCellStyle -> {2 -> Opacity[0.5, LightBlue]},
MeshCellShapeFunction -> {0 -> ({Opacity[1, Yellow], Disk[#, .05],
Text[Style[# /. rule, Red, 16], #]} &)}]
Also
labeled = Labeled[#, # /. rule] & /@ MeshCoordinates[ConvexHullMesh[xy]];
Show[ConvexHullMesh[xy], ListPlot[labeled], Graphics[Point[xy]], Frame ->True]
Revision
Contrive some data.
SeedRandom[42];
With[{n = 42},
data = Transpose[{RandomReal[1., {n, 2}], RandomSample[Range[100], n]}]];
Short[data, 3]
{{{0.425905, 0.391023}, 51}, <<40>>, {{0.359445, 0.00772549},24}}
Separating the points from the labels.
pts = data[[All, 1]];
lbls = data[[All, 2]];
Generating the convex hull.
ch = ConvexHullMesh[pts];
Extracting the boundary point labels.
bpts = MeshCoordinates[RegionBoundary[ch]];
blbls = Extract[lbls, Flatten[Position[pts, #] & /@ bpts, 1]]
{94, 36, 21, 1, 88, 2, 14, 24}
Making the labels into graphics elements.
labels = MapThread[Text[#1, #2] &, {blbls, bpts}];
Showing the combined graphics.
Show[ch, Graphics[{Point[pts], labels}], Axes -> True]
Of course, the labels can be fancied up by using Inset
rather than Text
labels =
MapThread[
Inset[
Graphics[{FaceForm[White], EdgeForm[Black], Disk[], Text[Style[#1, 9]]}],
#2, Automatic, Scaled[.0475]] &,
{blbls, bpts}];
Show[ch, Graphics[{Point[pts], labels}],
Method -> {"AxesInFront" -> False}, Axes -> True]
There are potential shortcomings in using Rule
to map points to labels, which I have occasionally come across. The purpose in creating a NearestFunction
using Nearest
below to map coordinates {x, y}
to a label
is overcome these shortcoming, at only a small expense of computational time. Given the general nature of the question, this seemed the best approach.
Often in an application, one might arrive at coordinates in various ways. If we're using floating-point numbers, rounding error might make simple rules of the form {x, y} -> label
fail, because the coordinates {x, y}
of the rule might not exactly match the computed coordinates in the figure. Or one might start with exact coordinates, which at some point might be numericized (converted to floating point), and again the replacement rule will fail. Nearest
takes care of those issues, unless rounding error is so great that one computed point ends up closer to a different point than the intended one (in such a case, the problem is completely different, a numerics one). Whether or not to numericized the points with N[]
depends on whether data
is already numericized; it's not strictly necessary in either case, but it should speed up nf
, which might be an issue with a very long list data
.
points = data[[All, 1]];
nf = Nearest[N@points -> data[[All, 2]]]; (* map coordinates to labels in data *)
hull = ConvexHullMesh[data[[All, 1]]];
With[{coords = MeshCoordinates[hull]},
Show[
MeshRegion[
coords,
MeshCells[hull, 2],
MeshCellLabel -> Table[{0, i} -> First@nf[coords[[i]]], {i, Length@coords}]
],
Axes -> True] (* or Frame -> True *)
]