0
$\begingroup$

Here are two very nice programs I got from the nice guys here helping me to solve my questions. The first one can be used to change the positions of the vertices and to delete the unwanted edges of a RandomGraph, the second one can be used to delete the unwanted vertices by double-clicking on them. Now I want to combine these functions into one single program. I failed to do so. Please help.

(*  Program one: 
    Edges can be deleted by double-clicking on them
    Ctrl+Drag can joint two nodes
*)
DynamicModule[{rg, refreshed = True},
 rg = RandomGraph[{5, 7}, DirectedEdges -> True];
 edglst = EdgeList[rg];
 vlst = VertexList[rg];
 VPOS = VertexCoordinates /. AbsoluteOptions[rg, VertexCoordinates];
 OVP = VPOS = 
   Rescale[#, 1 + Through[{Min, Max}[VPOS]], {0, 1}] & /@ VPOS;

 eventhlers = 
  MapThread[
   EventHandler[#, {"MouseDown" :> 
       If[CurrentValue["MouseClickCount"] == 2, 
         (epos = First@Position[edglst, #];
         edglst = Drop[edglst, epos ];
         eventhlers = Drop[eventhlers, epos ])]}] &, {edglst}];

 EventHandler[g = Dynamic@Graph[vlst, eventhlers,
     VertexCoordinates -> VPOS,
     VertexSize -> {.02, .02},
     VertexLabels -> "Name",
     PlotRange -> 1,
     EdgeStyle -> {Thick}],
  {"MouseDown" :> (
     If[CurrentValue["ControlKey"],
      If[refreshed,
       pos = MousePosition["Graphics"];
       ind = Position[VPOS, Nearest[VPOS, pos][[1]]][[1, 1]];
       tmp = ind;
       vnumb = Length[vlst] + 1;
       AppendTo[vlst, vnumb];
       AppendTo[VPOS, pos];
       AppendTo[edglst, ind <-> vnumb];
       ind = vnumb;
       refreshed = False;
       ],
      pos = MousePosition["Graphics"];
      ind = Position[VPOS, Nearest[VPOS, pos][[1]]][[1, 1]];
      ]),
   "MouseDragged" :>
    (
     VPOS[[ind]] = MousePosition["Graphics"];
     refreshed = True;
     If[! CurrentValue["ControlKey"],
      OVP = VPOS]
     ),

   "MouseUp" :>
    (
     If[CurrentValue["ControlKey"],
      pos2 = MousePosition["Graphics"];
      ind2 = Position[OVP, Nearest[OVP, pos2][[1]]][[1, 1]];
      vnumb = Length[vlst];
      vlst = Drop[vlst, -1];
      VPOS = Drop[VPOS, -1];
      edglst = Drop[edglst, -1];
      If[! MemberQ[edglst, tmp \[DirectedEdge] ind2] , 
       AppendTo[edglst, tmp \[DirectedEdge] ind2];

       eventhlers = 
        MapThread[
         EventHandler[#, {"MouseDown" :> 
             If[CurrentValue["MouseClickCount"] == 2, 
              (epos = First@Position[edglst, #];
               edglst = Drop[edglst, epos ];
               eventhlers = Drop[eventhlers, epos ])]}] &, {edglst}];
       ]
      ])
   },
  PassEventsDown -> True
  ]
 ]


(* Second program: nodes can be deleted by double-clicking on them *)
DynamicModule[{rg},
 rg = RandomGraph[{5, 7}, DirectedEdges -> True];
 edglst = EdgeList[rg];
 vlst = VertexList[rg];
 VPOS = VertexCoordinates /. AbsoluteOptions[rg, VertexCoordinates];
 VPOS = Rescale[#, 1 + Through[{Min, Max}[VPOS]], {0, 1}] & /@ VPOS;

 Vnthlrs = 
  MapThread[
   EventHandler[#, {"MouseDown" :> 
       If[CurrentValue["MouseClickCount"] == 2, 
        (ep = First@Position[vlst, #];
         vlst = Drop[vlst, ep];
         VPOS = Drop[VPOS, ep];
         edglst = 
          Delete[edglst, Map[List, Position[edglst, #][[All, 1]]]];
         Vnthlrs = Drop[Vnthlrs, ep])]}] &, {vlst}];

 g = Dynamic@Graph[Vnthlrs,
    edglst,
    VertexCoordinates -> VPOS,
    VertexSize -> {.02, .02},
    VertexLabels -> "Name",
    PlotRange -> 1,
    EdgeStyle -> {Thick}
    ]
 ]

Finally, I figured out how to combine these two programs. For operations details, pls refer to the comments at the top of the combined program. It is now clear to me that multiple EventHandlers can be wrapped around each other and created dynamically in MM.

(* Combined program:
  * Edges can be deleted by double-clicking on them(click right on the edge)
  * Nodes can be deleted by double-clicking on them(double-click right on the top of the node)
  * Drag the node to change its position (drag when close to the node, NOT on top of it)
  * Ctrl+Drag the node (begin Ctrl+Drag just close to the node, NOT right on top of it)
    to another node to joint them. *)

DynamicModule[{rg, refreshed = True}, 
 rg = RandomGraph[{#, # + 4}, DirectedEdges -> True] & [ RandomInteger[{5, 7}]];
 edglst = EdgeList[rg];
 vlst = VertexList[rg];
 vnumb = Length[vlst];
 VPOS = VertexCoordinates /. AbsoluteOptions[rg, VertexCoordinates];
 OVP = VPOS = 
   Rescale[#, 1 + Through[{Min, Max}[VPOS]], {0, 1}] & /@ VPOS;

 (* double click to delete edge *)
 eventhlers = 
  MapThread[
   EventHandler[#, {"MouseDown" :> 
       If[CurrentValue["MouseClickCount"] == 2, 
         (epos = First@Position[edglst, #];
         edglst = Drop[edglst, epos];
         eventhlers = Drop[eventhlers, epos])]}] &, {edglst}];
 (* double click to delete vertex *)
 Vnthlrs = 
  MapThread[
   EventHandler[#, {"MouseDown" :> 
       If[CurrentValue["MouseClickCount"] == 2, 
         (ep = First@Position[vlst, #];
         vlst = Drop[vlst, ep];

         edglst = 
          Delete[edglst, Map[List, Position[edglst, #][[All, 1]]]];

         eventhlers = 
          MapThread[

           EventHandler[#, {"MouseDown" :> 
               If[CurrentValue["MouseClickCount"] == 2, 
                 (epos = First@Position[edglst, #];
                 edglst = Drop[edglst, epos];
                 eventhlers = Drop[eventhlers, epos])]}] &, {edglst}];
         VPOS = Drop[VPOS, ep];
         OVP = VPOS;
         Vnthlrs = Drop[Vnthlrs, ep])]}] &, {vlst}];
 EventHandler[g = Dynamic@Graph[
     Vnthlrs,
     eventhlers,
     VertexCoordinates -> VPOS,
     VertexSize -> {.02, .02},
     VertexLabels -> "Name",
     PlotRange -> 1,
     EdgeStyle -> {Thick}
     ],
  {
   "MouseDown" :>
    (
     If[CurrentValue["ControlKey"],
      If[refreshed,
       pos = MousePosition["Graphics"];
       ind = Position[VPOS, Nearest[VPOS, pos][[1]]][[1, 1]];
       tmp = vlst[[ind]];
       vnumb = vnumb + 1;
       AppendTo[vlst, vnumb];
       AppendTo[edglst, tmp \[DirectedEdge] vnumb];
       AppendTo[VPOS, pos];

       (* double click to delete edge *)
       eventhlers = 
        MapThread[
         EventHandler[#, {"MouseDown" :> 
             If[CurrentValue["MouseClickCount"] == 2, 
               (epos = First@Position[edglst, #];
               edglst = Drop[edglst, epos];
               eventhlers = Drop[eventhlers, epos])]}] &, {edglst}];
       (* double click to delete vertex *)
       Vnthlrs = 
        MapThread[
         EventHandler[#, {"MouseDown" :> 
             If[CurrentValue["MouseClickCount"] == 2, 
               (ep = First@Position[vlst, #];
               vlst = Drop[vlst, ep];


               edglst = 
                Delete[edglst, 
                 Map[List, Position[edglst, #][[All, 1]]]];


               eventhlers = 
                MapThread[
                 EventHandler[#, {"MouseDown" :> 
                    If[CurrentValue["MouseClickCount"] == 2, 
                    (epos = First@Position[edglst, #];
                    edglst = Drop[edglst, epos];

                    eventhlers = 
                    Drop[eventhlers, epos])]}] &, {edglst}];
               VPOS = Drop[VPOS, ep];
               OVP = VPOS;
               Vnthlrs = Drop[Vnthlrs, ep])]}] &, {vlst}];
       ind = Position[vlst, vnumb][[1]][[1]];
       refreshed = False;],
      pos = MousePosition["Graphics"];
      ind = Position[VPOS, Nearest[VPOS, pos][[1]]][[1, 1]];]
     ),

   "MouseDragged" :> (VPOS[[ind]] = MousePosition["Graphics"];
     refreshed = True;
     If[! CurrentValue["ControlKey"], OVP = VPOS]),

   "MouseUp" :> (
     If[CurrentValue["ControlKey"],
      pos2 = MousePosition["Graphics"];
      ind2 = Position[OVP, Nearest[OVP, pos2][[1]]][[1, 1]];
      tmp2=vlst[[ind2]];
      vlst = Drop[vlst, -1];
      edglst = Drop[edglst, -1];
      VPOS = Drop[VPOS, -1];

      (* double click to delete edge *)
      eventhlers = 
       MapThread[
        EventHandler[#, {"MouseDown" :> 
            If[CurrentValue["MouseClickCount"] == 2, 
              (epos = First@Position[edglst, #];
              edglst = Drop[edglst, epos];
              eventhlers = Drop[eventhlers, epos])]}] &, {edglst}];
      (* double click to delete vertex *)
      Vnthlrs = 
       MapThread[
        EventHandler[#, {"MouseDown" :> 
            If[CurrentValue["MouseClickCount"] == 2, 
              (ep = First@Position[vlst, #];
              vlst = Drop[vlst, ep];


              edglst = 
               Delete[edglst, 
                Map[List, Position[edglst, #][[All, 1]]]];


              eventhlers = 
               MapThread[
               EventHandler[#, {"MouseDown" :> 
                   If[CurrentValue["MouseClickCount"] == 2, 
                    (epos = First@Position[edglst, #];
                    edglst = Drop[edglst, epos];

                    eventhlers = 
                    Drop[eventhlers, epos])]}] &, {edglst}];
              VPOS = Drop[VPOS, ep];
              OVP = VPOS;
              Vnthlrs = Drop[Vnthlrs, ep])]}] &, {vlst}];

      If[! MemberQ[edglst, tmp \[DirectedEdge] tmp2], 
      AppendTo[edglst, tmp \[DirectedEdge] tmp2];
       eventhlers = 
        MapThread[
         EventHandler[#, {"MouseDown" :> 

             If[CurrentValue["MouseClickCount"] == 2, 
               (epos = First@Position[edglst, #];
               edglst = Drop[edglst, epos];
               eventhlers = Drop[eventhlers, epos])]}] &, {edglst}];]]
     )
   }, PassEventsDown -> True
  ]
 ]

It seems the above program can be more user friendly if it allows people to add nodes. So here comes this new function to it.

(* Combined program:
  * Edges can be deleted by double-clicking on them(click right on the edge)
  * Nodes can be deleted by double-clicking on them(double-click right on the top of the node)
  * Drag the node to change its position (drag when close to the node, NOT on top of it)
  * Ctrl+Drag the node (begin Ctrl+Drag just close to the node, NOT right on top of it)
    to another node to joint them.
  * Shift+double-click at space to add new node    *)      


DynamicModule[{rg, refreshed = True}, 
 rg = RandomGraph[{#, # + 4}, DirectedEdges -> True] &[RandomInteger[{5, 7}]];
 edglst = EdgeList[rg];
 vlst = VertexList[rg];
 vnumb = Length[vlst];
 VPOS = VertexCoordinates /. AbsoluteOptions[rg, VertexCoordinates];
 OVP = VPOS = 
   Rescale[#, 1 + Through[{Min, Max}[VPOS]], {0, 1}] & /@ VPOS;

 (*double click to delete edge*)
 eventhlers = 
  MapThread[
   EventHandler[#, {"MouseDown" :> 
       If[CurrentValue["MouseClickCount"] == 2, 
     (epos = First@Position[edglst, #];
     edglst = Drop[edglst, epos];
     eventhlers = Drop[eventhlers, epos])]}] &, {edglst}];

 (*double click to delete vertex*)
 Vnthlrs = 
  MapThread[
   EventHandler[#, {"MouseDown" :> 
       If[CurrentValue["MouseClickCount"] == 2, 
         (ep = First@Position[vlst, #];
         vlst = Drop[vlst, ep];
         edglst = 
          Delete[edglst, Map[List, Position[edglst, #][[All, 1]]]];
         eventhlers = 
          MapThread[

           EventHandler[#, {"MouseDown" :> 
               If[CurrentValue["MouseClickCount"] == 2, 
                 (epos = First@Position[edglst, #];
                 edglst = Drop[edglst, epos];
                 eventhlers = Drop[eventhlers, epos])]}] &, {edglst}];
         VPOS = Drop[VPOS, ep];
         OVP = VPOS;
         Vnthlrs = Drop[Vnthlrs, ep])]}] &, {vlst}];

 EventHandler[
  g = Dynamic@
    Graph[Vnthlrs, eventhlers, VertexCoordinates -> VPOS, 
     VertexSize -> {.02, .02}, VertexLabels -> "Name", PlotRange -> 1,
      EdgeStyle -> {Thick}],
  {
   "MouseDown" :>
    (
     If[CurrentValue["ControlKey"],
      If[refreshed,
       pos = MousePosition["Graphics"];
       ind = Position[VPOS, Nearest[VPOS, pos][[1]]][[1, 1]];
       tmp = vlst[[ind]];
       vnumb = vnumb + 1;
       AppendTo[vlst, vnumb];
       AppendTo[edglst, tmp \[DirectedEdge] vnumb];
       AppendTo[VPOS, pos];
       (*double click to delete edge*)
       eventhlers = 
        MapThread[
         EventHandler[#, {"MouseDown" :> 
             If[CurrentValue["MouseClickCount"] == 2, 
                (epos = First@Position[edglst, #];
               edglst = Drop[edglst, epos];
               eventhlers = Drop[eventhlers, epos])]}] &, {edglst}];
       (*double click to delete vertex*)
       Vnthlrs = 
        MapThread[
         EventHandler[#, {"MouseDown" :> 
             If[CurrentValue["MouseClickCount"] == 2, 
               (ep = First@Position[vlst, #];
               vlst = Drop[vlst, ep];

               edglst = 
                Delete[edglst, 
                 Map[List, Position[edglst, #][[All, 1]]]];

               eventhlers = 
                MapThread[
                 EventHandler[#, {"MouseDown" :> 
                    If[CurrentValue["MouseClickCount"] == 2, 
                    (epos = First@Position[edglst, #];
                    edglst = Drop[edglst, epos];

                    eventhlers = 
                    Drop[eventhlers, epos])]}] &, {edglst}];
               VPOS = Drop[VPOS, ep];
               OVP = VPOS;
               Vnthlrs = Drop[Vnthlrs, ep])]}] &, {vlst}];
       ind = Position[vlst, vnumb][[1]][[1]];
       refreshed = False;],
      (*Not Controlkey*)
      If[! CurrentValue["ShiftKey"],
       (*Not shiftkey*)
       pos = MousePosition["Graphics"];
       ind = Position[VPOS, Nearest[VPOS, pos][[1]]][[1, 1]],
       (* shiftkey*)
       If[CurrentValue["MouseClickCount"] == 2,
        vRange = Range[Length[vlst] + 1];
        NewN = 
         Take[vRange, 
           Position[FreeQ[vlst, #] & /@ vRange, True][[1]] ][[1]];
        AppendTo[vlst, NewN];
        AppendTo[VPOS, MousePosition["Graphics"]];
        OVP = VPOS;
        (*double click to delete vertex*)
        Vnthlrs = 
         MapThread[
          EventHandler[#, {"MouseDown" :> 
              If[CurrentValue["MouseClickCount"] == 2, 
                (ep = First@Position[vlst, #];
                vlst = Drop[vlst, ep];

                edglst = 
                 Delete[edglst, 
                  Map[List, Position[edglst, #][[All, 1]]]];

                eventhlers = 
                 MapThread[
                  EventHandler[#, {"MouseDown" :> 
                    If[CurrentValue["MouseClickCount"] == 2, 
                    (epos = First@Position[edglst, #];
                    edglst = Drop[edglst, epos];

                    eventhlers = 
                    Drop[eventhlers, epos])]}] &, {edglst}];
                VPOS = Drop[VPOS, ep];
                OVP = VPOS;
                vnumb = vnumb + 1;
                Vnthlrs = Drop[Vnthlrs, ep])]}] &, {vlst}];
         ](*double clicked*)
        ]
      ](*Controlkey*)
     ),

   "MouseDragged" :> (VPOS[[ind]] = MousePosition["Graphics"];
     refreshed = True;
     If[! CurrentValue["ControlKey"], OVP = VPOS]),

   "MouseUp" :> (
     If[CurrentValue["ControlKey"],
      pos2 = MousePosition["Graphics"];
      ind2 = Position[OVP, Nearest[OVP, pos2][[1]]][[1, 1]];

      vlst = Drop[vlst, -1];
      edglst = Drop[edglst, -1];
      VPOS = Drop[VPOS, -1];

      (*double click to delete edge*)
      eventhlers = 
       MapThread[
        EventHandler[#, {"MouseDown" :> 
            If[CurrentValue["MouseClickCount"] == 2, 
              (epos = First@Position[edglst, #];
              edglst = Drop[edglst, epos];
              eventhlers = Drop[eventhlers, epos])]}] &, {edglst}];

      (*double click to delete vertex*)
      Vnthlrs = 
       MapThread[
        EventHandler[#, {"MouseDown" :> 
            If[CurrentValue["MouseClickCount"] == 2, 
               (ep = First@Position[vlst, #];
              vlst = Drop[vlst, ep];

              edglst = 
               Delete[edglst, 
                Map[List, Position[edglst, #][[All, 1]]]];

              eventhlers = 
               MapThread[
                EventHandler[#, {"MouseDown" :> 
                    If[CurrentValue["MouseClickCount"] == 2, 
                    (epos = First@Position[edglst, #];
                    edglst = Drop[edglst, epos];

                    eventhlers = 
                    Drop[eventhlers, epos])]}] &, {edglst}];
              VPOS = Drop[VPOS, ep];
              OVP = VPOS;
              Vnthlrs = Drop[Vnthlrs, ep])]}] &, {vlst}];
      tmp2 = vlst[[ind2]];
      If[! MemberQ[edglst, tmp \[DirectedEdge] tmp2], 
       AppendTo[edglst, tmp \[DirectedEdge] tmp2];

       eventhlers = 
        MapThread[
         EventHandler[#, {"MouseDown" :> 
             If[CurrentValue["MouseClickCount"] == 2, 
               (epos = First@Position[edglst, #];
               edglst = Drop[edglst, epos];
               eventhlers = Drop[eventhlers, epos])]}] &, {edglst}];
       ]])}, PassEventsDown -> True
  ]
 ]
$\endgroup$
2
  • $\begingroup$ Why do you keep updating this instead of your answer in the original question? Please post it there so that it is easier to find :) $\endgroup$ – rm -rf Jul 14 '14 at 0:00
  • $\begingroup$ @rm-rf Because this question had been labelled as Duplicate, there is nowhere I can put my final findings as answer. Actually this question is totally different from my original. $\endgroup$ – Putterboy Jul 14 '14 at 1:46

Browse other questions tagged or ask your own question.