# How do I make my Graph vertices into letters that are positioned correctly with respect to the ends of my edges?

I am using

mappingGraph[mapping_, chr_: "", rot_: 0] := Graph[
RotateRight[letters, rot],
Flatten@ MapIndexed[
Style[#1, If[First[#1] == chr, Thick, Dashed ], ColorData[100][First[#2]]] &,
rules /@ cycles[mapping],
{2}],
VertexCoordinates -> ({Cos@#, Sin@#} & /@ Range[0, 2 Pi - 1/26, 2 Pi/26]),
VertexLabels -> Placed["Name", Center],
VertexShapeFunction -> ({EdgeForm[White], White, Disk[#1, .02]} &),
VertexStyle -> Flatten@MapIndexed[
letter[#] -> ColorData[100][First[#2]] &,
cycles[mapping],
{2}],
VertexLabelStyle -> Flatten@MapIndexed[
letter[#] -> {Bold, ColorData[100][First[#2]]} &,
cycles[mapping],
{2}],
EdgeShapeFunction -> (If[#[[1]] != #[[-1]], {Arrowheads[If[#2[[1]] == chr, {{0.04, 1}}, {{0.02, 0.2}, {0.02, 0.8}}]], Arrow[BSplineCurve[{#[[1]], {0, 0}, #[[-1]]}, SplineWeights -> {2, 1, 2}]]}, Opacity[0]] &),
ImageSize -> Large];


where

letters = CharacterRange["A", "Z"];
letterIndex[l_] := letterIndex[l] = First@FirstPosition[letters, l];
letter[i_] := letter[i] = letters[[i]];


and

cycles[mapping_] := Identity @@ PermutationCycles[letterIndex /@ Characters[mapping]];
rules[cycle_] := Thread[# \[DirectedEdge] RotateLeft[#]] &[letter /@ cycle];


to create a figure representing a permutation of the letters of the alphabet, in which I distinguish cycles and (optionally) highlight a specified letter (optionally rotated by a certain number of letters).

I'm trying to get the vertices to be the letters themselves, distinguished by cycle, but I'm having trouble getting results that are satisfactory. I get clipping of the highlighted arrowhead (or too much fiddling the get the arrowhead not clipped) and of the arrows in general, and the whole thing seems to sensitive to scattered values that I can only guess at: in particular the position of the highlighted arrowhead, and the radius of the Disk used for the vertex.

For example

mappingGraph["AJDKSIRUXBLHWTMCQGZNPYFVOE", "S", 3]


gives

in which the arrow pointing at "Z" is truncated, while the start of that arrow, at "S" gets too close to the letter, as are several of the others (e.g., at "P" and "B"), while some — for example "G" — look fine. Frustratingly, each figure seems to have different arrows and letters that work out.

How do I make my Graph vertices into letters that are positioned correctly with respect to the ends of my edges? Is there an idiomatic way to do this that doesn't involve so many scattered values.

Minimally the arrows should end at the same place relative to every letter (e.g. see "Z" vs "I"), and that place should leave just enough space between the end of the arrows and the letter (e.g "J", but not "B", and certainly not "Z" or "P"). Moreover, the letters should be correctly centered (there a bit off here) and establishing the correct positioning shouldn't (at least ideally shouldn't) require endless tweaking and testing of fiddly settings like arrowhead positions (e.g. each time the highlighted letter is changed or the letter font size is adjusted). I expect I'm just missing some idiom for making vertices into letters.

• Can you check if using the second argument of Arrow, e.g., Arrow[BSplineCurve[{#[[1]], {0, 0}, #[[-1]]}, SplineWeights -> {2, 1, 2}],.05] give what you need? – kglr Apr 3 '15 at 5:04

You could add set back to your EdgeShapeFunction:

EdgeShapeFunction -> (If[#[[1]] != #[[-1]], {Arrowheads[
If[#2[[1]] == chr, {{0.04, 1}}, {{0.02, 0.2}, {0.02, 0.8}}]],
Arrow[BSplineCurve[{#[[1]], {0, 0}, #[[-1]]},
SplineWeights -> {2, 1, 2}], .025]}, Opacity[0]] &)


• See, I knew someone would understand. – orome Apr 3 '15 at 21:36

This seems perfectly legible to me:

Arrowheads[If[#2[[1]] == chr,
{{0.04, .98}}, {{0.02, 0.2}, {0.02, 0.8}}]]


• That's exactly what I'm trying to avoid (see the question): it crops the arrowhead to Z, which then requires tweaking (to a different and only guessed at setting for each figure). – orome Apr 2 '15 at 22:46
• Clearly we have different standards for what constitutes an acceptable figure: Minimally the arrows should end at the same place relative to every letter (e.g. see "Z" vs "I" in your figure), and that place should leave just enough space between the end of the arrows and the letter (e.g "J", but not "B", and certainly not "Z" or "P"), and should point at the center of the letter (here it doesn't, e.g. "Z"). – orome Apr 2 '15 at 23:18
• Some of the difference in arrow-vertex separations at the teeny scale you mentioned is due to the simple nature of dashed lines. I suspect you or contributors can spend a few hours on this task and micro-adjust such end points to meet your standards. – David G. Stork Apr 2 '15 at 23:31
• Some is due to the dashed lines; but not all. I've edited the question to include an explicit statement of what's expected, so we don't get wrapped up in whether "my standards" are too demanding for an answer (unless they are in fact too much to expect of Mathematica, in which case that's an informative answer). – orome Apr 2 '15 at 23:40