10

Is it possible to interactively draw a Graph in Mathematica and obtain the adjacency list? Ideally, I'd like to be able to draw different styles of lines.

By interactively, I mean to add nodes and connections manually.

infinitezero
  • 1,419
  • 8
  • 18

4 Answers4

8

IGraph/M 0.6 includes IGGraphEditor[], which allows manipulating small graphs interactively.

enter image description here

This project is still in experimental stage, and all feedback is welcome! See the documentation on how to use this function. In short, Alt-click (Command-click on Mac) is used to create/delete vertices, or to delete edges.

Once you are done editing the graph, simply evaluate the cell that contains it to obtain a Graph expression. You can then apply IGAdjacencyList to it to get the adjacency list.

Big thanks to @Kuba for programming this!

Szabolcs
  • 234,956
  • 30
  • 623
  • 1,263
5

Give this a try and see if it does what you need:

<< GraphUtilities`

GraphEdit[]

Jason B.
  • 68,381
  • 3
  • 139
  • 286
  • This is the only built-in way, as of version 12.1. Unfortunately, it is quite outdated. There were some questions about implementing an interactive graph editor on this site, but there is no built-in and supported one. – Szabolcs Aug 24 '20 at 14:33
  • Well now this page seems to claim this is not needed because as of Version 10 it's built in. And looking at the first application of this function it appears that there is somehow a way to directly enter a graph, but it's very unclear how these graphs were entered especially given that the input is provided directly as input and not by invoking some function like GraphEdit[]. – Michael Jan 31 '22 at 00:32
5

Here's a simple function that can convert Graphics to a graph. With this, you can draw a simple graph with the Drawing Tools palette (http://reference.wolfram.com/language/tutorial/InteractiveGraphicsPalette.html) and then copy the graphics into this function:

graphicsToGraph[gr : _Graphics | _Graphics3D] := Module[{
    pts = Join @@ Cases[gr,
        Point[arg_] :> Replace[Setting[arg], lst : {__?NumericQ} :> {lst}],
        DirectedInfinity[1]
    ],
    edges1 = Cases[gr,
        Line[lst_] :> UndirectedEdge @@ Setting[lst][[{1, -1}]],
        DirectedInfinity[1]
    ],
    edges2 = Cases[gr,
        Arrow[lst_] :> DirectedEdge @@ Setting[lst][[{1, -1}]],
        DirectedInfinity[1]
    ],
    nf, vertices
},
    vertices = Range[Length[pts]];
Condition[
    nf = Nearest[pts -&gt; &quot;Index&quot;];
    Graph[
        vertices,
        Map[First @ nf[#, 1]&amp;, Join[edges1, edges2], {2}],
        VertexCoordinates -&gt; Thread[vertices -&gt; pts]
    ]
    ,
    Length[pts] &gt; 0
]

];

enter image description here

The function will look for Point, Line and Arrow primitives and then join them up in the most sensible way it can to make a graph. Only the begin and end points of lines/arrows will be kept, so you can draw segmented lines to avoid spaghetti.

Getting the adjacency matrix, vertex list and edge lists is easy from that point:

AdjacencyMatrix[graph]
VertexList[graph]
EdgeList[graph]
Sjoerd Smit
  • 23,370
  • 46
  • 75
3

I wrote some code for drawing a graph interactively using DynamicModule and EventHandler. You can add vertices with right click and edges with left-click. The adjacency list is printed at the bottom. Admittedly, the graph is stored as a list of points (in the graphics object coordinates), not a Graph. Also, the style of the edges is fixed.

DynamicModule[{newEdge = {}, edges = {}, vertices = {}, pos = {}},
 Dynamic[
  EventHandler[
   Column[{
     Framed@
      Graphics[{Black, Line[edges], PointSize[0.05], Red, 
        Point /@ vertices}, PlotRange -> {{0, 10}, {0, 10}}, 
       ImageSize -> 300],
     edges
     },
    Spacings -> 10
    ],
   {
    {"MouseClicked", 1} :> (
      If[Length[newEdge] > 0,
       Print["Please select a second vertex!"],
       pos = Round[MousePosition["Graphics"]];
       If [MemberQ[vertices, pos],
        Print["Vertex already exists!"],
        AppendTo[vertices, pos]
        ]
       ]
      ),
    {"MouseClicked", 2} :> (
      pos = Round[MousePosition["Graphics"]];
      If[MemberQ[vertices, pos],
       AppendTo[newEdge, pos];
       If[Length[newEdge] == 2,
        AppendTo[edges, newEdge];
        newEdge = {}
        ]
       ]
      )
    }
   ]
  ]
 ]

Example output is attached below.

Example of the result

JaM
  • 170
  • 7
  • 1
    Sorry if my question was unclear. This simply draws a Complete Graph, but I want to specify nodes and edges manually. – infinitezero Aug 24 '20 at 12:20