8
$\begingroup$

When vertex sizes are uniform, the arrows representing directed edges are nicely offset to avoid overlapping with vertices:

Graph[{1 -> 2, 2 -> 1}, VertexSize -> 1/5, 
 VertexStyle -> Opacity[0.5]]

Mathematica graphics

But when each vertex has a different size, arrows are no longer offset, and the arrowheads are covered by the vertices.

Graph[{1 -> 2, 2 -> 1}, VertexSize -> {1 -> 1/3, 2 -> 1/5}, 
 VertexStyle -> Opacity[0.5]]

Mathematica graphics

What is the simplest way to remedy this situation?

$\endgroup$
2
  • 2
    $\begingroup$ Graph[{1 -> 2, 2 -> 1}, VertexSize -> {1 -> 1/3, 2 -> 1/5}, VertexStyle -> Opacity[0.5], PerformanceGoal -> "Quality"]? $\endgroup$
    – halmir
    May 1, 2017 at 13:01
  • 1
    $\begingroup$ @halmir This is great. Please make that an answer. I would never have guessed that. Also, you yourself have handled this manually in one of your answers, I think ... $\endgroup$
    – Szabolcs
    May 1, 2017 at 16:18

2 Answers 2

8
$\begingroup$

Set PerformanceGoal -> "Quality" can help:

Graph[{1 -> 2, 2 -> 1}, VertexSize -> {1 -> 1/3, 2 -> 1/5}, VertexStyle -> Opacity[0.5], 
        PerformanceGoal -> "Quality"]

Mathematica graphics

$\endgroup$
3
  • 2
    $\begingroup$ For Graph the default PerformanceGoal is $PerformanceGoal which normally evaluates to "Quality". It looks like a bug that despite this for Graph by default is used PerformanceGoal -> "Speed". Worth to report to tech support. $\endgroup$ May 1, 2017 at 17:21
  • 1
    $\begingroup$ How does the system figure out how much to offset the arrows by? I was surprised to see that the offsetting is perfect even if I use complex vertex shapes like polygons: VertexShapeFunction -> (Polygon@CirclePoints[#1, Max[#3], 3] &). The tip of the arrow is always touching the vertex shape, no matter what custom shape I use. $\endgroup$
    – Szabolcs
    May 1, 2017 at 17:28
  • $\begingroup$ I see that it is done through DynamicLocation, which you used in some of your answers. I wonder if it is possible to force these constructs to be used even if I set a custom EdgeShapeFunction. $\endgroup$
    – Szabolcs
    May 1, 2017 at 17:46
7
$\begingroup$

Revised

My previous suggestion was not sufficient. Here is a better approach, although still not ideal.

I don't know how to achieve proper Arrow objects without generating the Graph object and inspecting its properties in order to figure out proper Arrow setbacks. Rather than using the "Nearest" vertex size spec (the default), here is how one could use two passes with the "Scaled" vertex size spec. The "Scaled" vertex size spec uses sizes relative to the diagonal of the vertex coordinates bounding box.

sizeRules = {1->0.5,2->0.5,3->0.3,4->0.4,5->0.5} /. r_Real:>{"Scaled", r/5};
edges={1->2,1->3,1->5,2->1,2->4,2->5,3->2,4->1,4->5,5->3,5->4};

g = Graph[
    edges,
    VertexSize->sizeRules,
    VertexStyle->Opacity[0.5]
];

boundingBox = CoordinateBounds[VertexCoordinates /. AbsoluteOptions[g, VertexCoordinates]];
diag = Norm[Subtract @@@ boundingBox];

actualSizeRules = sizeRules /. {"Scaled", r_} :> r diag/2;
Graph[
    edges,
    VertexSize -> sizeRules,
    VertexStyle -> Opacity[0.5],
    EdgeShapeFunction -> (Arrow[#1, List@@#2 /. actualSizeRules]&)
]

enter image description here

$\endgroup$
5
  • $\begingroup$ It's a pity that the edge shape function does not have direct access to the graph, so we have to repeat the sizes for it. $\endgroup$
    – Szabolcs
    Apr 28, 2017 at 21:51
  • $\begingroup$ Agreed, although designing a good pure function interface into the graph's properties might be why it doesn't exist now. $\endgroup$
    – Carl Woll
    Apr 28, 2017 at 21:58
  • $\begingroup$ Something is not quite right about this. Consider sizeRules = {1 -> 0.5, 2 -> 0.5, 3 -> 0.3, 4 -> 0.4, 5 -> 0.5}; edges = {1 -> 2, 1 -> 3, 1 -> 5, 2 -> 1, 2 -> 4, 2 -> 5, 3 -> 2, 4 -> 1, 4 -> 5, 5 -> 3, 5 -> 4}; and Graph[ edges, VertexSize -> sizeRules, VertexStyle -> Opacity[0.5], EdgeShapeFunction -> (Arrow[#1, (List @@ #2 /. sizeRules)] &) ]. There is an extra scaling of about 0.3 on the vertex sizes. $\endgroup$
    – Szabolcs
    Apr 28, 2017 at 22:15
  • $\begingroup$ This must be because vertex sizes are taken to be relative to the shortest link, as I understand. Can I get this scaling factor somehow without measuring the shortest link? $\endgroup$
    – Szabolcs
    Apr 28, 2017 at 22:17
  • $\begingroup$ @Szabolcs I think you have to measure, but I think measuring the overall diagonal is easier than measuring the shortest link. I've modified my answer to do so. It would be nice if there were something more direct, I'll ask around and see. $\endgroup$
    – Carl Woll
    Apr 29, 2017 at 1:18

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.