4
$\begingroup$

In GraphPlot, I'd like to use VertexRenderingFunction (VRF) and have the resulting object behave the same way under dragging verticies as it does when I do not use VRF. The same issue occurs for EdgeRenderingFunction (ERF) and dragging edges.

Here's a MWE:

g = {1 -> 2, 2 -> 3, 3 -> 4, 4 -> 1};
{
  GraphPlot[g]
  ,
  GraphPlot[g, VertexRenderingFunction -> ({Blue, Disk[#1, 0.01]} &)]
}

Without VRF, I can click (sufficiently many times) on a node, drag it around, and the graph deforms without losing connections between the node and edges - see element one in the picture below. With VRF, if I click on a node, it behaves like a distinct graphics object that does not maintain connectivity to the appropriate edges - element two in the picture. The problem.

I'm guessing this has to do with how Mathematica generates the graphs since their InputForms are different:

 InputForm[GraphPlot[g]]

 (*Graphics[Annotation[GraphicsComplex[{{0., 0.9997532360813222}, 
 {0.9993931236462025, 1.0258160108662504}, {1.0286626995939243, 
 0.026431169015735057}, {0.02872413637035287, 0.}}, 
 {{RGBColor[0.5, 0., 0.], Line[{{1, 2}, {2, 3}, {3, 4}, {4, 1}}]}, 
 {RGBColor[0, 0, 0.7], Tooltip[Point[1], 1], Tooltip[Point[2], 2], 
 Tooltip[Point[3], 3], Tooltip[Point[4], 4]}}, {}], 
 VertexCoordinateRules -> {{0., 0.9997532360813222}, 
 {0.9993931236462025, 1.0258160108662504}, {1.0286626995939243, 
 0.026431169015735057}, {0.02872413637035287, 0.}}], 
 FrameTicks -> None, PlotRange -> All, PlotRangePadding -> 
 Scaled[0.1], AspectRatio -> Automatic]*)

vs.

In[159]:= InputForm[GraphPlot[g, VertexRenderingFunction -> ({Blue, Disk[#1, 0.01]} &)]]

(* Out[159]//InputForm=
Graphics[Annotation[GraphicsGroup[
{GraphicsComplex[{{0., 0.9997532360813222}, {0.9993931236462025, 
1.0258160108662504}, {1.0286626995939243, 0.026431169015735057}, 
{0.02872413637035287, 0.}}, {RGBColor[0.5, 0., 0.], 
Line[{{1, 2}, {2, 3}, {3, 4}, {4, 1}}]}, {}], 
{{RGBColor[0, 0, 1], Disk[{0., 0.9997532360813222}, 0.01]}, 
{RGBColor[0, 0, 1], Disk[{0.9993931236462025, 
1.0258160108662504}, 0.01]}, {RGBColor[0, 0, 1], 
Disk[{1.0286626995939243, 0.026431169015735057}, 0.01]}, 
{RGBColor[0, 0, 1], Disk[{0.02872413637035287, 0.}, 0.01]}}}, 
ContentSelectable -> True], VertexCoordinateRules -> {{0., 
0.9997532360813222}, {0.9993931236462025, 1.0258160108662504}, 
{1.0286626995939243, 0.026431169015735057}, {0.02872413637035287, 
0.}}], FrameTicks -> None, PlotRange -> All, 
PlotRangePadding -> Scaled[0.1], AspectRatio -> Automatic]*)

I'm interested in this because I want to draw more complicated graphs with a subset of vertices styled one way, another subset styled a different way, and so on. In this post, someone suggested just dragging around the rendered vertices after moving the edges, but:

  • This option is not feasible for more than a handful of verticies, especially if the verticies are supposed to be labeled in special ways.
  • If I want to use both ERF and VRF, then I have to move every piece of the graph individually.
  • It seems if Mathematica creates the non-VRF graphs in a way I like, then I should be able to duplicate the behavior on my own VRF, but I couldn't work out how from the InputForms.
  • The ability to click and drag edges is important because Mathematica does not render graphs the way I want them to appear (even under various "Methods->___"). So any solutions with different graph options (i.e. using Graph) should also offer a way to arbitrarily deform the output graph.
$\endgroup$
3
  • $\begingroup$ Please see the abstraction withVRF that I added. $\endgroup$
    – Mr.Wizard
    Feb 23, 2015 at 6:42
  • $\begingroup$ I edited the title in an effort to make it more concise and descriptive; I hope you do not mind. $\endgroup$
    – Mr.Wizard
    Feb 23, 2015 at 6:48
  • $\begingroup$ Fine with me. And your solution worked perfectly, thanks! $\endgroup$ Feb 23, 2015 at 22:04

1 Answer 1

4
$\begingroup$

For the vertices to be correctly movable their primitives must be positioned using the indexes of GraphicsComplex rather than direct Graphics coordinates. This way all primitives with the same index move together. I don't know of a way to make VertexRenderingFunction use these indexes natively, though I have not explored it. However since the default vertex points are created within the GraphicsComplex we can apply the vertex function in post-processing to achieve your goal:

g = {1 -> 2, 2 -> 3, 3 -> 4, 4 -> 1};

GraphPlot[g] /. Point[n_Integer] :> {Blue, Disk[n, 0.1]}

enter image description here

If you wish to use vertex labels you will need a slightly different replacement:

GraphPlot[g] /. 
  Tooltip[Point[n_Integer], label_] :>
    {Blue, Disk[n, 0.1], White, Text[label ~Style~ 18, n]}

enter image description here

If you already have your VertexRenderingFunction written here is an abstraction:

withVRF[VRF_][args__] := GraphPlot[args] /.
      Tooltip[Point[n_Integer], label_] :> VRF[n, label]

Example:

vertex = {White, EdgeForm[Black], Disk[#, .1], Black, Text[#2, #1]} &;

withVRF[vertex][g, DirectedEdges -> True]

enter image description here

$\endgroup$

Your Answer

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

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