7
$\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
    $\begingroup$ Graph[{1 -> 2, 2 -> 1}, VertexSize -> {1 -> 1/3, 2 -> 1/5}, VertexStyle -> Opacity[0.5], PerformanceGoal -> "Quality"]? $\endgroup$ – halmir May 1 '17 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 '17 at 16:18
5
$\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$
  • 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$ – Alexey Popkov May 1 '17 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 '17 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 '17 at 17:46
6
$\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$
  • $\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 '17 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 '17 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 '17 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 '17 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 '17 at 1:18

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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