How can I use the Python library networkx from Mathematica?How to use Mathematica functions in Python programs?Is there a way to run Python from within Mathematica?How to connect to an already running interactive Python session?How to get Python WolframClient library to connect with WolframKernel on Linux?

What benefits are there to blocking most search engines?

Mac is stuck in some kind of automatic layout windowing mode

Why can I ping 10.0.0.0/8 addresses from a 192.168.1.0/24 subnet?

We're all Greek here

Why did a young George Washington sign a document admitting to assassinating a French military officer?

Who became a professor?

Find the percentage

How do lasers measure short distances (<1cm) when electronics are too slow for time-of-flight to work?

Difference between $HOME and ~

Coffee Grounds and Gritty Butter Cream Icing

How to discipline overeager engineer

What is /dev/null and why can't I use hx on it?

Remove one or more fields, delimited by a "-", at end of line

How are steel imports supposed to threaten US national security?

Why is there "Il" in "Il mio tesoro intanto"?

Landing Hero: Product snippets VS illustrations

Why has Donald Trump's popularity remain so stable over a rather long period of time?

The work of mathematicians outside their professional environment

Is insurance company’s preferred auto shop biased?

What is the size of Neverwinter?

I am confused with the word order when putting a sentence into passé composé with reflexive verbs

Does the Creighton Method of Natural Family Planning have a failure rate of 3.2% or less?

Was Wayne Brady considered a guest star on the original "Whose Line Is It Anyway?"

Had there been instances of national states banning harmful imports before the Opium wars?



How can I use the Python library networkx from Mathematica?


How to use Mathematica functions in Python programs?Is there a way to run Python from within Mathematica?How to connect to an already running interactive Python session?How to get Python WolframClient library to connect with WolframKernel on Linux?






.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty
margin-bottom:0;

.everyonelovesstackoverflowposition:absolute;height:1px;width:1px;opacity:0;top:0;left:0;pointer-events:none;








21












$begingroup$


Is there an easy way to access the Python library networkx from Mathematica?



The improvements to ExternalEvaluate in Mathematica 12.0 should make this feasible.










share|improve this question









$endgroup$




















    21












    $begingroup$


    Is there an easy way to access the Python library networkx from Mathematica?



    The improvements to ExternalEvaluate in Mathematica 12.0 should make this feasible.










    share|improve this question









    $endgroup$
















      21












      21








      21


      11



      $begingroup$


      Is there an easy way to access the Python library networkx from Mathematica?



      The improvements to ExternalEvaluate in Mathematica 12.0 should make this feasible.










      share|improve this question









      $endgroup$




      Is there an easy way to access the Python library networkx from Mathematica?



      The improvements to ExternalEvaluate in Mathematica 12.0 should make this feasible.







      graphs-and-networks interoperability external-calls python






      share|improve this question













      share|improve this question











      share|improve this question




      share|improve this question










      asked Apr 17 at 11:48









      SzabolcsSzabolcs

      172k18 gold badges468 silver badges1004 bronze badges




      172k18 gold badges468 silver badges1004 bronze badges























          1 Answer
          1






          active

          oldest

          votes


















          29














          $begingroup$

          Mathematica 12.0 brings two new features that make this easier to do than it was before:



          • ExternalFunction


          • Wolfram Client for Python


          Below we implement a function nxFunction that automatically handles translating Mathematica expressions of interest to Python, as well as converting the results back. The usage will be



          nxFunction["someNetworkxFunction"][graph, positionalArg2, "keyword1" -> keywordArgValue]


          Here is a barebones example that serves as a proof of concept. (Improvements posted as additional answers are very welcome!)



          Set up external session



          First, make sure that the Python you are using has networkx installed, and start an external session. In the below example I am using an Anaconda virtualenv named "py37" on macOS. Adjust as necessary for your machine.



          py = StartExternalSession["Python", 
          "Executable" -> AbsoluteFileName["~/anaconda/envs/py37/bin/python"]]


          Load the package:



          ExternalEvaluate[py, "import networkx as nx"]


          Mathematica -> Python conversion



          We are going to use two Python helper function to translate arguments into the correct form. Most networkx functions that take a graph will take it as the first argument. This Python function takes a vertex list, an edge list and a graph type, and translates them to a networkx object. The rest of the arguments/options are passed as normal arguments / keyword arguments.



          nxFun = ExternalFunction[py, "
          def nxfun(vertices, edges, gtype, fname, args, kwargs):
          fun = getattr(nx, fname)
          GraphClass = 'su': nx.Graph, 'sd': nx.DiGraph, 'mu': nx.MultiGraph, 'md': nx.MultiDiGraph[gtype]
          g = GraphClass()
          g.add_nodes_from(vertices)
          g.add_edges_from(edges)
          return fun(g, *args, **kwargs)
          "]


          The following is for calling networkx functions that do not take a graph argument:



          nxPlainFun = ExternalFunction[py, "
          def nxplainfun(fname, args, kwargs):
          fun = getattr(nx, fname)
          return fun(*args, **kwargs)
          "]


          Now we create Mathematica functions that call the above Python functions:



          ClearAll[nxGraphQ]
          nxGraphQ[_?MixedGraphQ] = False;
          nxGraphQ[_?GraphQ] = True;
          nxGraphQ[_] = False;

          (* first argument is a graph *)
          nxFunction[name_][g_?nxGraphQ, args___, kwargs : OptionsPattern[]] :=
          nxFun[
          VertexList[g],
          List @@@ EdgeList[g],
          If[MultigraphQ[g],
          If[DirectedGraphQ[g], "md", "mu"],
          If[DirectedGraphQ[g], "sd", "su"]
          ],
          name,
          args,
          Association[kwargs]
          ]

          (* first argument is not a graph *)
          nxFunction[name_][args___, kwargs : OptionsPattern[]] :=
          nxPlainFun[
          name, args, Association[kwargs]
          ]


          Python -> Mathematica conversion



          We create a custom serializer for networkx graphs, as described here:



          • https://reference.wolfram.com/language/WolframClientForPython/docpages/advanced_usages.html#extending-serialization-writing-an-encoder

          ExternalEvaluate[py,
          "
          from wolframclient.language import wl
          from wolframclient.serializers import wolfram_encoder

          @wolfram_encoder.dispatch(nx.Graph)
          def encode_animal(serializer, graph):
          return serializer.encode(wl.Graph(graph.nodes, wl.Apply(wl.UndirectedEdge, graph.edges, [1])))

          @wolfram_encoder.dispatch(nx.DiGraph)
          def encode_animal(serializer, graph):
          return serializer.encode(wl.Graph(graph.nodes, wl.Apply(wl.DirectedEdge, graph.edges, [1])))
          "]


          Try it out



          Create a test graph:



          SeedRandom[42]
          g = RandomGraph[10, 20, DirectedEdges -> True]


          Compute the betweenness:



          nxFunction["betweenness_centrality"][g]
          (* <|1 -> 0.256944, 2 -> 0.0416667, 3 -> 0., 4 -> 0.333333,
          5 -> 0.0277778, 6 -> 0.236111, 7 -> 0.25, 8 -> 0.111111, 9 -> 0.,
          10 -> 0.0763889|> *)


          Compute betweenness without normalization (and test keyword arguments):



          nxFunction["betweenness_centrality"][g, "normalized" -> False]
          (* <|1 -> 18.5, 2 -> 3., 3 -> 0., 4 -> 24., 5 -> 2., 6 -> 17.,
          7 -> 18., 8 -> 8., 9 -> 0., 10 -> 5.5|> *)


          Compare with Mathematica's result:



          BetweennessCentrality[g]
          (* 18.5, 3., 0., 24., 2., 17., 18., 8., 0., 5.5 *)


          A networkx function that returns a graph:



          nxFunction["grid_graph"][3, 4]


          enter image description here



          Graph[nxFunction["margulis_gabber_galil_graph"][6], 
          VertexLabels -> Automatic]


          enter image description here



          nxFunction["hexagonal_lattice_graph"][6, 7]


          enter image description here



          Modify existing graphs:



          nxFunction["ego_graph"][GridGraph[5, 6], 1, 3]


          enter image description here



          nxFunction["mycielskian"][GridGraph[3, 3]]


          enter image description here



          Compute minimal cycle basis:



          nxFunction["minimum_cycle_basis"][GridGraph[3, 4]]

          (* 1, 2, 4, 5, 2, 3, 5, 6, 4, 5, 7, 8, 5, 6, 8, 9, 7, 8, 10, 11, 8, 9, 11, 12 *)


          This is a first proof of concept. Improvement and suggestions are most welcome. I encourage everyone to post new answers either improving this one, or presenting independent approaches.






          share|improve this answer











          $endgroup$














          • $begingroup$
            +1 as always!!!! For clarification: what limitations, if any, have you found with the python=>mma conversion?
            $endgroup$
            – CA Trevillian
            Jun 28 at 20:22













          Your Answer








          StackExchange.ready(function()
          var channelOptions =
          tags: "".split(" "),
          id: "387"
          ;
          initTagRenderer("".split(" "), "".split(" "), channelOptions);

          StackExchange.using("externalEditor", function()
          // Have to fire editor after snippets, if snippets enabled
          if (StackExchange.settings.snippets.snippetsEnabled)
          StackExchange.using("snippets", function()
          createEditor();
          );

          else
          createEditor();

          );

          function createEditor()
          StackExchange.prepareEditor(
          heartbeatType: 'answer',
          autoActivateHeartbeat: false,
          convertImagesToLinks: false,
          noModals: true,
          showLowRepImageUploadWarning: true,
          reputationToPostImages: null,
          bindNavPrevention: true,
          postfix: "",
          imageUploader:
          brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
          contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/4.0/"u003ecc by-sa 4.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
          allowUrls: true
          ,
          onDemand: true,
          discardSelector: ".discard-answer"
          ,immediatelyShowMarkdownHelp:true
          );



          );














          draft saved

          draft discarded
















          StackExchange.ready(
          function ()
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fmathematica.stackexchange.com%2fquestions%2f195380%2fhow-can-i-use-the-python-library-networkx-from-mathematica%23new-answer', 'question_page');

          );

          Post as a guest















          Required, but never shown

























          1 Answer
          1






          active

          oldest

          votes








          1 Answer
          1






          active

          oldest

          votes









          active

          oldest

          votes






          active

          oldest

          votes









          29














          $begingroup$

          Mathematica 12.0 brings two new features that make this easier to do than it was before:



          • ExternalFunction


          • Wolfram Client for Python


          Below we implement a function nxFunction that automatically handles translating Mathematica expressions of interest to Python, as well as converting the results back. The usage will be



          nxFunction["someNetworkxFunction"][graph, positionalArg2, "keyword1" -> keywordArgValue]


          Here is a barebones example that serves as a proof of concept. (Improvements posted as additional answers are very welcome!)



          Set up external session



          First, make sure that the Python you are using has networkx installed, and start an external session. In the below example I am using an Anaconda virtualenv named "py37" on macOS. Adjust as necessary for your machine.



          py = StartExternalSession["Python", 
          "Executable" -> AbsoluteFileName["~/anaconda/envs/py37/bin/python"]]


          Load the package:



          ExternalEvaluate[py, "import networkx as nx"]


          Mathematica -> Python conversion



          We are going to use two Python helper function to translate arguments into the correct form. Most networkx functions that take a graph will take it as the first argument. This Python function takes a vertex list, an edge list and a graph type, and translates them to a networkx object. The rest of the arguments/options are passed as normal arguments / keyword arguments.



          nxFun = ExternalFunction[py, "
          def nxfun(vertices, edges, gtype, fname, args, kwargs):
          fun = getattr(nx, fname)
          GraphClass = 'su': nx.Graph, 'sd': nx.DiGraph, 'mu': nx.MultiGraph, 'md': nx.MultiDiGraph[gtype]
          g = GraphClass()
          g.add_nodes_from(vertices)
          g.add_edges_from(edges)
          return fun(g, *args, **kwargs)
          "]


          The following is for calling networkx functions that do not take a graph argument:



          nxPlainFun = ExternalFunction[py, "
          def nxplainfun(fname, args, kwargs):
          fun = getattr(nx, fname)
          return fun(*args, **kwargs)
          "]


          Now we create Mathematica functions that call the above Python functions:



          ClearAll[nxGraphQ]
          nxGraphQ[_?MixedGraphQ] = False;
          nxGraphQ[_?GraphQ] = True;
          nxGraphQ[_] = False;

          (* first argument is a graph *)
          nxFunction[name_][g_?nxGraphQ, args___, kwargs : OptionsPattern[]] :=
          nxFun[
          VertexList[g],
          List @@@ EdgeList[g],
          If[MultigraphQ[g],
          If[DirectedGraphQ[g], "md", "mu"],
          If[DirectedGraphQ[g], "sd", "su"]
          ],
          name,
          args,
          Association[kwargs]
          ]

          (* first argument is not a graph *)
          nxFunction[name_][args___, kwargs : OptionsPattern[]] :=
          nxPlainFun[
          name, args, Association[kwargs]
          ]


          Python -> Mathematica conversion



          We create a custom serializer for networkx graphs, as described here:



          • https://reference.wolfram.com/language/WolframClientForPython/docpages/advanced_usages.html#extending-serialization-writing-an-encoder

          ExternalEvaluate[py,
          "
          from wolframclient.language import wl
          from wolframclient.serializers import wolfram_encoder

          @wolfram_encoder.dispatch(nx.Graph)
          def encode_animal(serializer, graph):
          return serializer.encode(wl.Graph(graph.nodes, wl.Apply(wl.UndirectedEdge, graph.edges, [1])))

          @wolfram_encoder.dispatch(nx.DiGraph)
          def encode_animal(serializer, graph):
          return serializer.encode(wl.Graph(graph.nodes, wl.Apply(wl.DirectedEdge, graph.edges, [1])))
          "]


          Try it out



          Create a test graph:



          SeedRandom[42]
          g = RandomGraph[10, 20, DirectedEdges -> True]


          Compute the betweenness:



          nxFunction["betweenness_centrality"][g]
          (* <|1 -> 0.256944, 2 -> 0.0416667, 3 -> 0., 4 -> 0.333333,
          5 -> 0.0277778, 6 -> 0.236111, 7 -> 0.25, 8 -> 0.111111, 9 -> 0.,
          10 -> 0.0763889|> *)


          Compute betweenness without normalization (and test keyword arguments):



          nxFunction["betweenness_centrality"][g, "normalized" -> False]
          (* <|1 -> 18.5, 2 -> 3., 3 -> 0., 4 -> 24., 5 -> 2., 6 -> 17.,
          7 -> 18., 8 -> 8., 9 -> 0., 10 -> 5.5|> *)


          Compare with Mathematica's result:



          BetweennessCentrality[g]
          (* 18.5, 3., 0., 24., 2., 17., 18., 8., 0., 5.5 *)


          A networkx function that returns a graph:



          nxFunction["grid_graph"][3, 4]


          enter image description here



          Graph[nxFunction["margulis_gabber_galil_graph"][6], 
          VertexLabels -> Automatic]


          enter image description here



          nxFunction["hexagonal_lattice_graph"][6, 7]


          enter image description here



          Modify existing graphs:



          nxFunction["ego_graph"][GridGraph[5, 6], 1, 3]


          enter image description here



          nxFunction["mycielskian"][GridGraph[3, 3]]


          enter image description here



          Compute minimal cycle basis:



          nxFunction["minimum_cycle_basis"][GridGraph[3, 4]]

          (* 1, 2, 4, 5, 2, 3, 5, 6, 4, 5, 7, 8, 5, 6, 8, 9, 7, 8, 10, 11, 8, 9, 11, 12 *)


          This is a first proof of concept. Improvement and suggestions are most welcome. I encourage everyone to post new answers either improving this one, or presenting independent approaches.






          share|improve this answer











          $endgroup$














          • $begingroup$
            +1 as always!!!! For clarification: what limitations, if any, have you found with the python=>mma conversion?
            $endgroup$
            – CA Trevillian
            Jun 28 at 20:22
















          29














          $begingroup$

          Mathematica 12.0 brings two new features that make this easier to do than it was before:



          • ExternalFunction


          • Wolfram Client for Python


          Below we implement a function nxFunction that automatically handles translating Mathematica expressions of interest to Python, as well as converting the results back. The usage will be



          nxFunction["someNetworkxFunction"][graph, positionalArg2, "keyword1" -> keywordArgValue]


          Here is a barebones example that serves as a proof of concept. (Improvements posted as additional answers are very welcome!)



          Set up external session



          First, make sure that the Python you are using has networkx installed, and start an external session. In the below example I am using an Anaconda virtualenv named "py37" on macOS. Adjust as necessary for your machine.



          py = StartExternalSession["Python", 
          "Executable" -> AbsoluteFileName["~/anaconda/envs/py37/bin/python"]]


          Load the package:



          ExternalEvaluate[py, "import networkx as nx"]


          Mathematica -> Python conversion



          We are going to use two Python helper function to translate arguments into the correct form. Most networkx functions that take a graph will take it as the first argument. This Python function takes a vertex list, an edge list and a graph type, and translates them to a networkx object. The rest of the arguments/options are passed as normal arguments / keyword arguments.



          nxFun = ExternalFunction[py, "
          def nxfun(vertices, edges, gtype, fname, args, kwargs):
          fun = getattr(nx, fname)
          GraphClass = 'su': nx.Graph, 'sd': nx.DiGraph, 'mu': nx.MultiGraph, 'md': nx.MultiDiGraph[gtype]
          g = GraphClass()
          g.add_nodes_from(vertices)
          g.add_edges_from(edges)
          return fun(g, *args, **kwargs)
          "]


          The following is for calling networkx functions that do not take a graph argument:



          nxPlainFun = ExternalFunction[py, "
          def nxplainfun(fname, args, kwargs):
          fun = getattr(nx, fname)
          return fun(*args, **kwargs)
          "]


          Now we create Mathematica functions that call the above Python functions:



          ClearAll[nxGraphQ]
          nxGraphQ[_?MixedGraphQ] = False;
          nxGraphQ[_?GraphQ] = True;
          nxGraphQ[_] = False;

          (* first argument is a graph *)
          nxFunction[name_][g_?nxGraphQ, args___, kwargs : OptionsPattern[]] :=
          nxFun[
          VertexList[g],
          List @@@ EdgeList[g],
          If[MultigraphQ[g],
          If[DirectedGraphQ[g], "md", "mu"],
          If[DirectedGraphQ[g], "sd", "su"]
          ],
          name,
          args,
          Association[kwargs]
          ]

          (* first argument is not a graph *)
          nxFunction[name_][args___, kwargs : OptionsPattern[]] :=
          nxPlainFun[
          name, args, Association[kwargs]
          ]


          Python -> Mathematica conversion



          We create a custom serializer for networkx graphs, as described here:



          • https://reference.wolfram.com/language/WolframClientForPython/docpages/advanced_usages.html#extending-serialization-writing-an-encoder

          ExternalEvaluate[py,
          "
          from wolframclient.language import wl
          from wolframclient.serializers import wolfram_encoder

          @wolfram_encoder.dispatch(nx.Graph)
          def encode_animal(serializer, graph):
          return serializer.encode(wl.Graph(graph.nodes, wl.Apply(wl.UndirectedEdge, graph.edges, [1])))

          @wolfram_encoder.dispatch(nx.DiGraph)
          def encode_animal(serializer, graph):
          return serializer.encode(wl.Graph(graph.nodes, wl.Apply(wl.DirectedEdge, graph.edges, [1])))
          "]


          Try it out



          Create a test graph:



          SeedRandom[42]
          g = RandomGraph[10, 20, DirectedEdges -> True]


          Compute the betweenness:



          nxFunction["betweenness_centrality"][g]
          (* <|1 -> 0.256944, 2 -> 0.0416667, 3 -> 0., 4 -> 0.333333,
          5 -> 0.0277778, 6 -> 0.236111, 7 -> 0.25, 8 -> 0.111111, 9 -> 0.,
          10 -> 0.0763889|> *)


          Compute betweenness without normalization (and test keyword arguments):



          nxFunction["betweenness_centrality"][g, "normalized" -> False]
          (* <|1 -> 18.5, 2 -> 3., 3 -> 0., 4 -> 24., 5 -> 2., 6 -> 17.,
          7 -> 18., 8 -> 8., 9 -> 0., 10 -> 5.5|> *)


          Compare with Mathematica's result:



          BetweennessCentrality[g]
          (* 18.5, 3., 0., 24., 2., 17., 18., 8., 0., 5.5 *)


          A networkx function that returns a graph:



          nxFunction["grid_graph"][3, 4]


          enter image description here



          Graph[nxFunction["margulis_gabber_galil_graph"][6], 
          VertexLabels -> Automatic]


          enter image description here



          nxFunction["hexagonal_lattice_graph"][6, 7]


          enter image description here



          Modify existing graphs:



          nxFunction["ego_graph"][GridGraph[5, 6], 1, 3]


          enter image description here



          nxFunction["mycielskian"][GridGraph[3, 3]]


          enter image description here



          Compute minimal cycle basis:



          nxFunction["minimum_cycle_basis"][GridGraph[3, 4]]

          (* 1, 2, 4, 5, 2, 3, 5, 6, 4, 5, 7, 8, 5, 6, 8, 9, 7, 8, 10, 11, 8, 9, 11, 12 *)


          This is a first proof of concept. Improvement and suggestions are most welcome. I encourage everyone to post new answers either improving this one, or presenting independent approaches.






          share|improve this answer











          $endgroup$














          • $begingroup$
            +1 as always!!!! For clarification: what limitations, if any, have you found with the python=>mma conversion?
            $endgroup$
            – CA Trevillian
            Jun 28 at 20:22














          29














          29










          29







          $begingroup$

          Mathematica 12.0 brings two new features that make this easier to do than it was before:



          • ExternalFunction


          • Wolfram Client for Python


          Below we implement a function nxFunction that automatically handles translating Mathematica expressions of interest to Python, as well as converting the results back. The usage will be



          nxFunction["someNetworkxFunction"][graph, positionalArg2, "keyword1" -> keywordArgValue]


          Here is a barebones example that serves as a proof of concept. (Improvements posted as additional answers are very welcome!)



          Set up external session



          First, make sure that the Python you are using has networkx installed, and start an external session. In the below example I am using an Anaconda virtualenv named "py37" on macOS. Adjust as necessary for your machine.



          py = StartExternalSession["Python", 
          "Executable" -> AbsoluteFileName["~/anaconda/envs/py37/bin/python"]]


          Load the package:



          ExternalEvaluate[py, "import networkx as nx"]


          Mathematica -> Python conversion



          We are going to use two Python helper function to translate arguments into the correct form. Most networkx functions that take a graph will take it as the first argument. This Python function takes a vertex list, an edge list and a graph type, and translates them to a networkx object. The rest of the arguments/options are passed as normal arguments / keyword arguments.



          nxFun = ExternalFunction[py, "
          def nxfun(vertices, edges, gtype, fname, args, kwargs):
          fun = getattr(nx, fname)
          GraphClass = 'su': nx.Graph, 'sd': nx.DiGraph, 'mu': nx.MultiGraph, 'md': nx.MultiDiGraph[gtype]
          g = GraphClass()
          g.add_nodes_from(vertices)
          g.add_edges_from(edges)
          return fun(g, *args, **kwargs)
          "]


          The following is for calling networkx functions that do not take a graph argument:



          nxPlainFun = ExternalFunction[py, "
          def nxplainfun(fname, args, kwargs):
          fun = getattr(nx, fname)
          return fun(*args, **kwargs)
          "]


          Now we create Mathematica functions that call the above Python functions:



          ClearAll[nxGraphQ]
          nxGraphQ[_?MixedGraphQ] = False;
          nxGraphQ[_?GraphQ] = True;
          nxGraphQ[_] = False;

          (* first argument is a graph *)
          nxFunction[name_][g_?nxGraphQ, args___, kwargs : OptionsPattern[]] :=
          nxFun[
          VertexList[g],
          List @@@ EdgeList[g],
          If[MultigraphQ[g],
          If[DirectedGraphQ[g], "md", "mu"],
          If[DirectedGraphQ[g], "sd", "su"]
          ],
          name,
          args,
          Association[kwargs]
          ]

          (* first argument is not a graph *)
          nxFunction[name_][args___, kwargs : OptionsPattern[]] :=
          nxPlainFun[
          name, args, Association[kwargs]
          ]


          Python -> Mathematica conversion



          We create a custom serializer for networkx graphs, as described here:



          • https://reference.wolfram.com/language/WolframClientForPython/docpages/advanced_usages.html#extending-serialization-writing-an-encoder

          ExternalEvaluate[py,
          "
          from wolframclient.language import wl
          from wolframclient.serializers import wolfram_encoder

          @wolfram_encoder.dispatch(nx.Graph)
          def encode_animal(serializer, graph):
          return serializer.encode(wl.Graph(graph.nodes, wl.Apply(wl.UndirectedEdge, graph.edges, [1])))

          @wolfram_encoder.dispatch(nx.DiGraph)
          def encode_animal(serializer, graph):
          return serializer.encode(wl.Graph(graph.nodes, wl.Apply(wl.DirectedEdge, graph.edges, [1])))
          "]


          Try it out



          Create a test graph:



          SeedRandom[42]
          g = RandomGraph[10, 20, DirectedEdges -> True]


          Compute the betweenness:



          nxFunction["betweenness_centrality"][g]
          (* <|1 -> 0.256944, 2 -> 0.0416667, 3 -> 0., 4 -> 0.333333,
          5 -> 0.0277778, 6 -> 0.236111, 7 -> 0.25, 8 -> 0.111111, 9 -> 0.,
          10 -> 0.0763889|> *)


          Compute betweenness without normalization (and test keyword arguments):



          nxFunction["betweenness_centrality"][g, "normalized" -> False]
          (* <|1 -> 18.5, 2 -> 3., 3 -> 0., 4 -> 24., 5 -> 2., 6 -> 17.,
          7 -> 18., 8 -> 8., 9 -> 0., 10 -> 5.5|> *)


          Compare with Mathematica's result:



          BetweennessCentrality[g]
          (* 18.5, 3., 0., 24., 2., 17., 18., 8., 0., 5.5 *)


          A networkx function that returns a graph:



          nxFunction["grid_graph"][3, 4]


          enter image description here



          Graph[nxFunction["margulis_gabber_galil_graph"][6], 
          VertexLabels -> Automatic]


          enter image description here



          nxFunction["hexagonal_lattice_graph"][6, 7]


          enter image description here



          Modify existing graphs:



          nxFunction["ego_graph"][GridGraph[5, 6], 1, 3]


          enter image description here



          nxFunction["mycielskian"][GridGraph[3, 3]]


          enter image description here



          Compute minimal cycle basis:



          nxFunction["minimum_cycle_basis"][GridGraph[3, 4]]

          (* 1, 2, 4, 5, 2, 3, 5, 6, 4, 5, 7, 8, 5, 6, 8, 9, 7, 8, 10, 11, 8, 9, 11, 12 *)


          This is a first proof of concept. Improvement and suggestions are most welcome. I encourage everyone to post new answers either improving this one, or presenting independent approaches.






          share|improve this answer











          $endgroup$



          Mathematica 12.0 brings two new features that make this easier to do than it was before:



          • ExternalFunction


          • Wolfram Client for Python


          Below we implement a function nxFunction that automatically handles translating Mathematica expressions of interest to Python, as well as converting the results back. The usage will be



          nxFunction["someNetworkxFunction"][graph, positionalArg2, "keyword1" -> keywordArgValue]


          Here is a barebones example that serves as a proof of concept. (Improvements posted as additional answers are very welcome!)



          Set up external session



          First, make sure that the Python you are using has networkx installed, and start an external session. In the below example I am using an Anaconda virtualenv named "py37" on macOS. Adjust as necessary for your machine.



          py = StartExternalSession["Python", 
          "Executable" -> AbsoluteFileName["~/anaconda/envs/py37/bin/python"]]


          Load the package:



          ExternalEvaluate[py, "import networkx as nx"]


          Mathematica -> Python conversion



          We are going to use two Python helper function to translate arguments into the correct form. Most networkx functions that take a graph will take it as the first argument. This Python function takes a vertex list, an edge list and a graph type, and translates them to a networkx object. The rest of the arguments/options are passed as normal arguments / keyword arguments.



          nxFun = ExternalFunction[py, "
          def nxfun(vertices, edges, gtype, fname, args, kwargs):
          fun = getattr(nx, fname)
          GraphClass = 'su': nx.Graph, 'sd': nx.DiGraph, 'mu': nx.MultiGraph, 'md': nx.MultiDiGraph[gtype]
          g = GraphClass()
          g.add_nodes_from(vertices)
          g.add_edges_from(edges)
          return fun(g, *args, **kwargs)
          "]


          The following is for calling networkx functions that do not take a graph argument:



          nxPlainFun = ExternalFunction[py, "
          def nxplainfun(fname, args, kwargs):
          fun = getattr(nx, fname)
          return fun(*args, **kwargs)
          "]


          Now we create Mathematica functions that call the above Python functions:



          ClearAll[nxGraphQ]
          nxGraphQ[_?MixedGraphQ] = False;
          nxGraphQ[_?GraphQ] = True;
          nxGraphQ[_] = False;

          (* first argument is a graph *)
          nxFunction[name_][g_?nxGraphQ, args___, kwargs : OptionsPattern[]] :=
          nxFun[
          VertexList[g],
          List @@@ EdgeList[g],
          If[MultigraphQ[g],
          If[DirectedGraphQ[g], "md", "mu"],
          If[DirectedGraphQ[g], "sd", "su"]
          ],
          name,
          args,
          Association[kwargs]
          ]

          (* first argument is not a graph *)
          nxFunction[name_][args___, kwargs : OptionsPattern[]] :=
          nxPlainFun[
          name, args, Association[kwargs]
          ]


          Python -> Mathematica conversion



          We create a custom serializer for networkx graphs, as described here:



          • https://reference.wolfram.com/language/WolframClientForPython/docpages/advanced_usages.html#extending-serialization-writing-an-encoder

          ExternalEvaluate[py,
          "
          from wolframclient.language import wl
          from wolframclient.serializers import wolfram_encoder

          @wolfram_encoder.dispatch(nx.Graph)
          def encode_animal(serializer, graph):
          return serializer.encode(wl.Graph(graph.nodes, wl.Apply(wl.UndirectedEdge, graph.edges, [1])))

          @wolfram_encoder.dispatch(nx.DiGraph)
          def encode_animal(serializer, graph):
          return serializer.encode(wl.Graph(graph.nodes, wl.Apply(wl.DirectedEdge, graph.edges, [1])))
          "]


          Try it out



          Create a test graph:



          SeedRandom[42]
          g = RandomGraph[10, 20, DirectedEdges -> True]


          Compute the betweenness:



          nxFunction["betweenness_centrality"][g]
          (* <|1 -> 0.256944, 2 -> 0.0416667, 3 -> 0., 4 -> 0.333333,
          5 -> 0.0277778, 6 -> 0.236111, 7 -> 0.25, 8 -> 0.111111, 9 -> 0.,
          10 -> 0.0763889|> *)


          Compute betweenness without normalization (and test keyword arguments):



          nxFunction["betweenness_centrality"][g, "normalized" -> False]
          (* <|1 -> 18.5, 2 -> 3., 3 -> 0., 4 -> 24., 5 -> 2., 6 -> 17.,
          7 -> 18., 8 -> 8., 9 -> 0., 10 -> 5.5|> *)


          Compare with Mathematica's result:



          BetweennessCentrality[g]
          (* 18.5, 3., 0., 24., 2., 17., 18., 8., 0., 5.5 *)


          A networkx function that returns a graph:



          nxFunction["grid_graph"][3, 4]


          enter image description here



          Graph[nxFunction["margulis_gabber_galil_graph"][6], 
          VertexLabels -> Automatic]


          enter image description here



          nxFunction["hexagonal_lattice_graph"][6, 7]


          enter image description here



          Modify existing graphs:



          nxFunction["ego_graph"][GridGraph[5, 6], 1, 3]


          enter image description here



          nxFunction["mycielskian"][GridGraph[3, 3]]


          enter image description here



          Compute minimal cycle basis:



          nxFunction["minimum_cycle_basis"][GridGraph[3, 4]]

          (* 1, 2, 4, 5, 2, 3, 5, 6, 4, 5, 7, 8, 5, 6, 8, 9, 7, 8, 10, 11, 8, 9, 11, 12 *)


          This is a first proof of concept. Improvement and suggestions are most welcome. I encourage everyone to post new answers either improving this one, or presenting independent approaches.







          share|improve this answer














          share|improve this answer



          share|improve this answer








          edited Apr 17 at 12:14

























          answered Apr 17 at 12:04









          SzabolcsSzabolcs

          172k18 gold badges468 silver badges1004 bronze badges




          172k18 gold badges468 silver badges1004 bronze badges














          • $begingroup$
            +1 as always!!!! For clarification: what limitations, if any, have you found with the python=>mma conversion?
            $endgroup$
            – CA Trevillian
            Jun 28 at 20:22

















          • $begingroup$
            +1 as always!!!! For clarification: what limitations, if any, have you found with the python=>mma conversion?
            $endgroup$
            – CA Trevillian
            Jun 28 at 20:22
















          $begingroup$
          +1 as always!!!! For clarification: what limitations, if any, have you found with the python=>mma conversion?
          $endgroup$
          – CA Trevillian
          Jun 28 at 20:22





          $begingroup$
          +1 as always!!!! For clarification: what limitations, if any, have you found with the python=>mma conversion?
          $endgroup$
          – CA Trevillian
          Jun 28 at 20:22



















          draft saved

          draft discarded















































          Thanks for contributing an answer to Mathematica Stack Exchange!


          • Please be sure to answer the question. Provide details and share your research!

          But avoid


          • Asking for help, clarification, or responding to other answers.

          • Making statements based on opinion; back them up with references or personal experience.

          Use MathJax to format equations. MathJax reference.


          To learn more, see our tips on writing great answers.




          draft saved


          draft discarded














          StackExchange.ready(
          function ()
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fmathematica.stackexchange.com%2fquestions%2f195380%2fhow-can-i-use-the-python-library-networkx-from-mathematica%23new-answer', 'question_page');

          );

          Post as a guest















          Required, but never shown





















































          Required, but never shown














          Required, but never shown












          Required, but never shown







          Required, but never shown

































          Required, but never shown














          Required, but never shown












          Required, but never shown







          Required, but never shown







          Popular posts from this blog

          Distance measures on a map of a game The 2019 Stack Overflow Developer Survey Results Are Inmin distance in a graphShortest distance path on contour plotHow to plot a tilted map?Finding points outside of a diskDelaunay link distanceAnnulus from GeoDisks: drawing a ring on a mapNegative Correlation DistanceFind distance along a path (GPS coordinates)Finding position at given distance in a GeoPathMathematics behind distance estimation using camera

          How to get a smooth, uniform ParametricPlot of a 2D Region?How to plot a complicated Region?How to exclude a region from ParametricPlotHow discretize a region placing vertices on a specific non-uniform gridHow to transform a Plot or a ParametricPlot into a RegionHow can I get a smooth plot of a bounded region?Smooth ParametricPlot3D with RegionFunction?Smooth border of a region ParametricPlotSmooth region boundarySmooth region plot from list of pointsGet minimum y of a certain x in a region

          Genealogie vun de Merowenger Vum Merowech bis zum Chilperich I. | Navigatiounsmenü