# How to labels for each point in a list of arbitrary length?

I am attempting to illustrate a mapping from an isoparametric space to a parent (x-y) space for a variety of finite element types. Here we consider the simplest case of a three noded triangular element. In the isoparametric space the triangle has nodes at {{1,0},{0,1},{0,1}} with interpolating functions n1=\xi n2=\eta n3=1-\xi-\eta. The isoparametric space maps to the parent space by

x=N1*x1=N2*x2+N3*x3, and y=N1*y1+N2*y2+N3*y3

Where xi is the x coordinate of the i-th node.

I am currently plotting this with the following code:

Step 1: Define interpolating functions and nodal positions in the isoparametric and parent spaces

n1lintri[x_, y_] := x
n2lintri[x_, y_] := y
n3lintri[x_, y_] := 1 - x - y

xltar = 1; yltar = 0;
xltbr = 0; yltbr = 1;
xltcr = 0; yltcr = 0;

xlta = 4; ylta = 3;
xltb = 1; yltb = 2;
xltc = 3; yltc = 1;


Step 2: Define domain to plot over

domain = Region[Triangle[{{0, 0}, {1, 0}, {0, 1}}]];


Step 3: Create parametric plot of isoparametric and parent domains and list of nodal points

lintri1 =
ParametricPlot[{
xltar n1lintri[x, y] + xltbr n2lintri[x, y] +
xltcr n3lintri[x, y],
yltar n1lintri[x, y] + yltbr n2lintri[x, y] +
yltcr n3lintri[x, y]}, {x, y} \[Element] domain, Frame -> False,
Axes -> False];
lintri1points = {{xltar, yltar}, {xltbr, yltbr}, {xltcr, yltcr}};

lintri2 =
ParametricPlot[{
xlta n1lintri[x, y] + xltb n2lintri[x, y] + xltc n3lintri[x, y],
ylta n1lintri[x, y] + yltb n2lintri[x, y] +
yltc n3lintri[x, y]}, {x, y} \[Element] domain, Frame -> False];
lintri2points = {{xlta, ylta}, {xltb, yltb}, {xltc, yltc}};


Step 4: Plot

Labeled[Show[lintri1,
ListPlot[lintri1points, PlotStyle -> {Red, PointSize[Large]},
Frame -> False], Axes -> True, AxesOrigin -> {0, 0},
PlotRange -> All], {Style["\[Xi]", 18, Black, Bold],
Style["\[Eta]", 18, Black, Bold]}, {Bottom, Left}]
Labeled[Show[lintri2,
ListPlot[lintri2points, PlotStyle -> {Red, PointSize[Large]},
Frame -> False], Axes -> True, AxesOrigin -> {0, 0},
PlotRange -> All], {Style["x", 18, Black, Bold],
Style["y", 18, Black, Bold]}, {Bottom, Left}]


Which yields the following

I would like to add labels numbering each node (in red) numbered sequentially with an offset so that the number is not on top of the node. For example

As elements can have many nodes I would prefer to not manually prescribe to offset for each label.

For a higher order element the corresponding code would be

Step 1:

n1quadtri[x_, y_] := x (2 x - 1)
n2quadtri[x_, y_] := y (2 y - 1)
n3quadtri[x_, y_] := (1 - x - y) (2 (1 - x - y) - 1)
n4quadtri[x_, y_] := 4 x y
n5quadtri[x_, y_] := 4 y (1 - x - y)
n6quadtri[x_, y_] := 4 (1 - x - y) x
xqtar = 1; yqtar = 0;
xqtbr = 0; yqtbr = 1;
xqtcr = 0; yqtcr = 0;
xqtdr = 0.5; yqtdr = 0.5;
xqter = 0; yqter = 0.5;
xqtfr = 0.5; yqtfr = 0;

xqta = 1; yqta = 0;
xqtb = 0; yqtb = 1;
xqtc = 0; yqtc = 0;
xqtd = 0.75; yqtd = 0.75;
xqte = 0.25; yqte = 0.5;
xqtf = 0.5; yqtf = 0;


Step 2:

domain = Region[Triangle[{{0, 0}, {1, 0}, {0, 1}}]];


Step 3:

quadtri1 =
ParametricPlot[{
y} \[Element] domain, Frame -> False, Axes -> False];
quadtri1points = {{xqtar, yqtar}, {xqtbr, yqtbr}, {xqtcr,
yqtcr}, {xqtdr, yqtdr}, {xqter, yqter}, {xqtfr, yqtfr}};

ParametricPlot[{
domain, Frame -> False, Axes -> False];
quadtri2points = {{xqta, yqta}, {xqtb, yqtb}, {xqtc, yqtc}, {xqtd,
yqtd}, {xqte, yqte}, {xqtf, yqtf}};


Step 4:

Labeled[Show[quadtri1,
Frame -> False], Axes -> True, AxesOrigin -> {0, 0},
PlotRange -> All], {Style["\[Xi]", 18, Black, Bold],
Style["\[Eta]", 18, Black, Bold]}, {Bottom, Left}]
Frame -> False], Axes -> True, AxesOrigin -> {0, 0},
PlotRange -> All], {Style["x", 18, Black, Bold],
Style["y", 18, Black, Bold]}, {Bottom, Left}]


Which yields

Which would ideally be labelled as

Any help would be appreciated.

• Would you kindly provide an example of how exactly you want the points labeled? While it is clear how you wish to have the outcome of the automated offset, the actual labeling you wish you have is not clear to me. Thank you. May 8, 2020 at 9:08
• @CATrevillian I have updated the question to make this clearer, hopefully it helps! May 8, 2020 at 9:33
• Most definitely! Last clarification on the desires for this question, regarding your use of Axes versus a 2-sided Frame--is there a reason for axes as opposed to a frame? And should the labels be placed within the axes/frame, or outside of the defined region? Which takes precedent? kglr provides a nice answer below which you can likely modify to sate your needs. May 8, 2020 at 10:12
• @CATrevillian For consistency with other figures I've made I'd prefer to have Axes instead of a Frame. Ideally I would like all labels (point labels and axis labels) to be in the defined region. May 8, 2020 at 10:22

ClearAll[labeledPoints]
labeledPoints[off_: .05] := Module[{rc = RegionCentroid[ConvexHullMesh @ #]},
{MapIndexed[Text[#2[[1]], # + off Normalize[# - rc]] &, #],
Red, PointSize[Large], Point @ #}] &;


Examples:

Labeled[Show[lintri1, Epilog -> labeledPoints[][lintri1points],
Axes -> True, AxesOrigin -> {0, 0},
PlotRange -> All], {Style["ξ", 18, Black, Bold],
Style["η", 18, Black, Bold]}, {Bottom, Left}]


Labeled[Show[lintri2, Epilog -> labeledPoints[.15][lintri2points],
Axes -> True, AxesOrigin -> {0, 0},
PlotRange -> All], {Style["x", 18, Black, Bold],
Style["y", 18, Black, Bold]}, {Bottom, Left}]


Labeled[Show[quadtri1, Epilog -> labeledPoints[][quadtri1points],
Axes -> True, AxesOrigin -> {0, 0},
PlotRange -> All], {Style["ξ", 18, Black, Bold],
Style["η", 18, Black, Bold]}, {Bottom, Left}]


Labeled[Show[quadtri2, Epilog -> labeledPoints[][quadtri2points],
Axes -> True, AxesOrigin -> {0, 0},
PlotRange -> All], {Style["x", 18, Black, Bold],
Style["y", 18, Black, Bold]}, {Bottom, Left}]


Use negative values for the offset parameter to place the labels inside. For example,

Labeled[Show[quadtri1, Epilog -> labeledPoints[-.05][quadtri1points],
Axes -> True, AxesOrigin -> {0, 0},
PlotRange -> All], {Style["ξ", 18, Black, Bold],
Style["η", 18, Black, Bold]}, {Bottom, Left}]


Labeled[Show[quadtri2, Epilog -> labeledPoints[-.05][quadtri2points],
Axes -> True, AxesOrigin -> {0, 0},
PlotRange -> All], {Style["x", 18, Black, Bold],
Style["y", 18, Black, Bold]}, {Bottom, Left}]


• This solution works really nicely! I wonder, is there a way to change the font size and font color of the node labels? And while it was not part of the original question, is it possible to include the axis labels in the image region? Currently using 'right click' and 'save as' does not include the axis labels in the saved image. May 8, 2020 at 11:16
• @DvanHuyssteen, you can change Text[#2[[1]],...] to Text[Style[#2[[1]], 6, Blue],..] to make the label font size 16 and color Blue. For the axes label issue, you can try Show[..., Frame->{{True, False}{, {True, False}},FrameLabels->{{Style["y", 18, Black, Bold], None},{ Style["y", 18, Black, Bold], None}}] instead of Labeled[Show[...], ..].
– kglr
May 8, 2020 at 11:28

I guess, the simplest way is:

 ll = {{-1, 1}, {1, 1}, {1, -1}};
ListPlot[Callout[#, ToString@Position[ll, #][[1, 1]]] & /@ ll]


Or you can take any labels from other list, using the Position[ll, #][[1, 1]]] as index for this label-list