How do I make the color of arrowheads in a graph different from the colors of the arrows?

I'm graphing a Markov process

mp = DiscreteMarkovProcess[{1, 0, 0}, ({
{0.6, 0.1, 0.3},
{0.2, 0.7, 0.1},
{0.3, 0.3, 0.4}
})];


and would like to have arrows whose thicknesses corresponds to the transition probabilities, with arrowheads of a different color in the exact center of each edge. But all my attempts end up a mess.

g = Graph[mp];
Scan[(PropertyValue[{g, #}, EdgeLabels] =
PropertyValue[{g, #}, "Probability"]) &, EdgeList[g]];
Scan[(PropertyValue[{g, #}, EdgeStyle] =
Thickness[PropertyValue[{g, #}, "Probability"]/20]]) &,
EdgeList[g]];
g


The thick edges leave gaps between their ends and the nodes of the graph, and I can't figure out how to change the color of the arrow heads so that they stand out against the color of the edges.

How can I change the color of the arrowheads in my figure. How can I avoid the gaps that appear between nodes and the ends of the edges?

• Take a look at EdgeShapeFunction. – wxffles May 7 '14 at 22:47
• @wxffles: Looks intriguing; but I'm not sure where to go with it. It seems to amount to "build it from scratch". – orome May 7 '14 at 23:21

Using an EdgeShapeFunction seems to do what you want. Adapting from the examples in the help:

ef[pts_List, e_] :=
Arrow[pts]}

g = Graph[mp];
Scan[(PropertyValue[{g, #}, EdgeLabels] =
PropertyValue[{g, #}, "Probability"]) &, EdgeList[g]];
Scan[(PropertyValue[{g, #}, EdgeStyle] =
Directive[GrayLevel[.7], Thickness[PropertyValue[{g, #}, "Probability"]/20]]) &,
EdgeList[g]];
Scan[(PropertyValue[{g, #}, EdgeShapeFunction] = ef) &, EdgeList[g]];
g


It's a bit ugly, with mysterious red dots within the arrowheads. But this only reflects how little time I've put into it. With some competence and patience I suspect it could do what you want.

Edit: Something nicer:

ef[pts_List, e_] := {Arrowheads[{{0.02, 0.65,
Graphics@{Red, EdgeForm[Gray], Polygon[{{-1.5, -1}, {1.5, 0}, {-1.5, 1}}]}
}}], Arrow[pts]}


• Is there a way to keep the arc shapes of the original? – orome May 8 '14 at 0:47
• Not easily as far as I can tell. It's just using the points that it gets passed. I'm not sure what the default EdgeShapeFunctions do to it. – wxffles May 8 '14 at 1:05
• @wxffles How to access the built-in set of arrow heads is described here. – Alexey Popkov May 8 '14 at 7:09

If you don't mind having a Graphics object, you can replace the Arrowheads directives with wxffles's Arrowheads specification, and get to keep the arc shapes of the orginial g:

arrowheads = Arrowheads[{{0.02, 0.65, Graphics@{Red, EdgeForm[Gray],
Polygon[{{-1.5, -1}, {1.5, 0}, {-1.5, 1}}]}}}];

g2 = Show[g] /. TagBox -> (# &) /. _Arrowheads :> arrowheads


If you have to have a Graph object, you can extract the edge primitives from g2 and use them as EdgeShapeFunction for g:

edgehapefunctions = Function /@
Cases[g2[[1]], {dirs___, _Arrowheads, _ArrowBox}, {0, Infinity}];

SetProperty[g, EdgeShapeFunction -> Thread[EdgeList[g] -> edgehapefunctions]]