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$
  • $\begingroup$ Please see the abstraction withVRF that I added. $\endgroup$ – Mr.Wizard Feb 23 '15 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 '15 at 6:48
  • $\begingroup$ Fine with me. And your solution worked perfectly, thanks! $\endgroup$ – jjstankowicz Feb 23 '15 at 22:04
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, privacy policy and cookie policy

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