{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "8cbd794e",
   "metadata": {},
   "source": [
    "# Using Apache Arrow Flight with Rocketgraph xGT\n",
    "\n",
    "The outline of this notebook:\n",
    "\n",
    "1. Generate a table of edges with random data.\n",
    "1. Bring edge table into an Arrow format.\n",
    "1. Send Arrow Flight to Rocketgraph xGT.\n",
    "1. Request to run a graph query on xGT.\n",
    "1. Bring results back as an Arrow Flight.\n",
    "1. Visualize results."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d639cf4a",
   "metadata": {},
   "source": [
    "## Generate edges with random data.\n",
    "\n",
    "First, set up parameters for edge table.\n",
    "\n",
    "The table will have four columns.\n",
    "The first two columns representing *source* and *target* of each edge.\n",
    "The other two columns representing edge attributes.\n",
    "\n",
    "The values of the first two columns are drawn randomly in the range of `1` to `NUM_NODES`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "a2b1bddc",
   "metadata": {},
   "outputs": [],
   "source": [
    "# Metadata of random data table\n",
    "NUM_ROWS=100\n",
    "NUM_NODES=10"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "972db386",
   "metadata": {},
   "outputs": [],
   "source": [
    "# Generate table\n",
    "import pandas as pd\n",
    "import random\n",
    "random.seed()\n",
    "alpha='abcdefghijklmnopqrstuvwxyz'\n",
    "\n",
    "data = {\n",
    "    'source': [random.randint(1, NUM_NODES) for _ in range(NUM_ROWS)],\n",
    "    'target': [random.randint(1, NUM_NODES) for _ in range(NUM_ROWS)],\n",
    "    'attr1' : [random.choice(alpha) for _ in range(NUM_ROWS)],\n",
    "    'attr2' : [random.choice(alpha) for _ in range(NUM_ROWS)],\n",
    "}\n",
    "df = pd.DataFrame(data)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "477fb1ed",
   "metadata": {},
   "source": [
    "## Bring edge table into Arrow format."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "88bf9969",
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "pyarrow.Table\n",
       "source: int64\n",
       "target: int64\n",
       "attr1: string\n",
       "attr2: string\n",
       "----\n",
       "source: [[6,6,9,2,4,...,7,3,8,9,10]]\n",
       "target: [[7,1,10,6,9,...,7,7,6,4,3]]\n",
       "attr1: [[\"x\",\"u\",\"u\",\"r\",\"k\",...,\"p\",\"x\",\"m\",\"q\",\"g\"]]\n",
       "attr2: [[\"a\",\"u\",\"j\",\"f\",\"d\",...,\"m\",\"g\",\"p\",\"g\",\"x\"]]"
      ]
     },
     "execution_count": 3,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "import pyarrow as pa\n",
    "import pyarrow.flight\n",
    "\n",
    "arrow_edges = pa.Table.from_pandas(df)\n",
    "arrow_edges"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "aaa788e4",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "['source', 'target', 'attr1', 'attr2']"
      ]
     },
     "execution_count": 4,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "arrow_edges.column_names"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "caefa9b0",
   "metadata": {},
   "source": [
    "## Send Arrow Flight to Rocketgraph xGT.\n",
    "\n",
    "First create frames on xGT to hold the graph data.\n",
    "\n",
    "Then establish a PyArrow Flight connection to the xGT server and send the data."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "05bd7685",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<xgt.graph.EdgeFrame at 0x1109d4370>"
      ]
     },
     "execution_count": 5,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "import xgt\n",
    "server = xgt.Connection()\n",
    "if 'arrow ' not in server.get_namespaces():\n",
    "  server.create_namespace('arrow')\n",
    "server.set_default_namespace('arrow')\n",
    "\n",
    "server.create_edge_frame_from_data(arrow_edges, 'Edge',\n",
    "                                   source='Node', target='Node',\n",
    "                                   source_key='source', target_key='target')"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "96f0a380",
   "metadata": {},
   "source": [
    "## Request to run a graph query on xGT."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "b579443d",
   "metadata": {
    "scrolled": true
   },
   "outputs": [],
   "source": [
    "query = \"\"\"\n",
    "MATCH (a)-[e1:Edge]->(b)-[e2:Edge]->(c)\n",
    "WHERE a <> b and b <> c and a <> c\n",
    "  AND e1.attr1 = e2.attr1\n",
    "RETURN DISTINCT a.id AS a, c.id AS c, e1.attr1 AS attr1\n",
    "INTO AnswerSet\n",
    "\"\"\"\n",
    "\n",
    "job = server.run_job(query)\n",
    "data = job.get_data(format='pandas')\n",
    "data"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d3e99d2d",
   "metadata": {},
   "source": [
    "## Bring results back\n",
    "\n",
    "Note that this process uses the *Arrow Flight* mechanism to transfer the `AnswerSet` data from the xGT server to the client."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "7db74d02",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "pyarrow.Table\n",
       "a: int64\n",
       "c: int64\n",
       "attr1: string\n",
       "----\n",
       "a: [[10,6,5,1,2,...,4,6,1,9,4]]\n",
       "c: [[7,3,3,10,3,...,3,5,6,4,6]]\n",
       "attr1: [[\"t\",\"q\",\"p\",\"u\",\"l\",...,\"q\",\"o\",\"r\",\"p\",\"q\"]]"
      ]
     },
     "execution_count": 7,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "answers = server.get_frame('AnswerSet').get_data(format='arrow')\n",
    "answers"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "3b321d3a",
   "metadata": {},
   "source": [
    "## Visualize results."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "id": "0fee52b8",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/svg+xml": [
       "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n",
       "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\"\n",
       " \"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">\n",
       "<!-- Generated by graphviz version 3.0.0 (20220226.1711)\n",
       " -->\n",
       "<!-- Pages: 1 -->\n",
       "<svg width=\"632pt\" height=\"674pt\"\n",
       " viewBox=\"0.00 0.00 632.00 674.00\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\">\n",
       "<g id=\"graph0\" class=\"graph\" transform=\"scale(1 1) rotate(0) translate(4 670)\">\n",
       "<polygon fill=\"white\" stroke=\"transparent\" points=\"-4,4 -4,-670 628,-670 628,4 -4,4\"/>\n",
       "<!-- 6 -->\n",
       "<g id=\"node1\" class=\"node\">\n",
       "<title>6</title>\n",
       "<ellipse fill=\"none\" stroke=\"black\" cx=\"234\" cy=\"-648\" rx=\"27\" ry=\"18\"/>\n",
       "<text text-anchor=\"middle\" x=\"234\" y=\"-644.3\" font-family=\"Times,serif\" font-size=\"14.00\">6</text>\n",
       "</g>\n",
       "<!-- 5 -->\n",
       "<g id=\"node4\" class=\"node\">\n",
       "<title>5</title>\n",
       "<ellipse fill=\"none\" stroke=\"black\" cx=\"457\" cy=\"-105\" rx=\"27\" ry=\"18\"/>\n",
       "<text text-anchor=\"middle\" x=\"457\" y=\"-101.3\" font-family=\"Times,serif\" font-size=\"14.00\">5</text>\n",
       "</g>\n",
       "<!-- 6&#45;&gt;5 -->\n",
       "<g id=\"edge24\" class=\"edge\">\n",
       "<title>6&#45;&gt;5</title>\n",
       "<path fill=\"none\" stroke=\"black\" d=\"M260.79,-645.72C338.42,-641.27 558,-623.28 558,-562 558,-562 558,-562 558,-191 558,-154.86 519.68,-131 490.25,-117.99\"/>\n",
       "<polygon fill=\"black\" stroke=\"black\" points=\"491.26,-114.62 480.68,-114 488.56,-121.08 491.26,-114.62\"/>\n",
       "<text text-anchor=\"middle\" x=\"567.5\" y=\"-362.3\" font-family=\"Times,serif\" font-size=\"14.00\">&quot;o&quot;</text>\n",
       "</g>\n",
       "<!-- 3 -->\n",
       "<g id=\"node6\" class=\"node\">\n",
       "<title>3</title>\n",
       "<ellipse fill=\"none\" stroke=\"black\" cx=\"121\" cy=\"-18\" rx=\"27\" ry=\"18\"/>\n",
       "<text text-anchor=\"middle\" x=\"121\" y=\"-14.3\" font-family=\"Times,serif\" font-size=\"14.00\">3</text>\n",
       "</g>\n",
       "<!-- 6&#45;&gt;3 -->\n",
       "<g id=\"edge2\" class=\"edge\">\n",
       "<title>6&#45;&gt;3</title>\n",
       "<path fill=\"none\" stroke=\"black\" d=\"M207.15,-645.29C158.1,-641.72 56.46,-632.07 28,-612 7.19,-597.32 0,-587.47 0,-562 0,-562 0,-562 0,-104 0,-78.53 8.69,-70.6 28,-54 44.3,-39.99 66.77,-31.32 85.53,-26.12\"/>\n",
       "<polygon fill=\"black\" stroke=\"black\" points=\"86.41,-29.51 95.24,-23.64 84.68,-22.73 86.41,-29.51\"/>\n",
       "<text text-anchor=\"middle\" x=\"9.5\" y=\"-318.8\" font-family=\"Times,serif\" font-size=\"14.00\">&quot;q&quot;</text>\n",
       "</g>\n",
       "<!-- 6&#45;&gt;3 -->\n",
       "<g id=\"edge19\" class=\"edge\">\n",
       "<title>6&#45;&gt;3</title>\n",
       "<path fill=\"none\" stroke=\"black\" d=\"M206.9,-646.94C153.97,-645.26 42,-633.27 42,-562 42,-562 42,-562 42,-104 42,-73.76 69.15,-49.77 91.62,-35.08\"/>\n",
       "<polygon fill=\"black\" stroke=\"black\" points=\"93.59,-37.98 100.24,-29.74 89.9,-32.03 93.59,-37.98\"/>\n",
       "<text text-anchor=\"middle\" x=\"51.5\" y=\"-318.8\" font-family=\"Times,serif\" font-size=\"14.00\">&quot;u&quot;</text>\n",
       "</g>\n",
       "<!-- 9 -->\n",
       "<g id=\"node10\" class=\"node\">\n",
       "<title>9</title>\n",
       "<ellipse fill=\"none\" stroke=\"black\" cx=\"234\" cy=\"-561\" rx=\"27\" ry=\"18\"/>\n",
       "<text text-anchor=\"middle\" x=\"234\" y=\"-557.3\" font-family=\"Times,serif\" font-size=\"14.00\">9</text>\n",
       "</g>\n",
       "<!-- 6&#45;&gt;9 -->\n",
       "<g id=\"edge22\" class=\"edge\">\n",
       "<title>6&#45;&gt;9</title>\n",
       "<path fill=\"none\" stroke=\"black\" d=\"M234,-629.8C234,-618.16 234,-602.55 234,-589.24\"/>\n",
       "<polygon fill=\"black\" stroke=\"black\" points=\"237.5,-589.18 234,-579.18 230.5,-589.18 237.5,-589.18\"/>\n",
       "<text text-anchor=\"middle\" x=\"243.5\" y=\"-600.8\" font-family=\"Times,serif\" font-size=\"14.00\">&quot;u&quot;</text>\n",
       "</g>\n",
       "<!-- 7 -->\n",
       "<g id=\"node2\" class=\"node\">\n",
       "<title>7</title>\n",
       "<ellipse fill=\"none\" stroke=\"black\" cx=\"313\" cy=\"-192\" rx=\"27\" ry=\"18\"/>\n",
       "<text text-anchor=\"middle\" x=\"313\" y=\"-188.3\" font-family=\"Times,serif\" font-size=\"14.00\">7</text>\n",
       "</g>\n",
       "<!-- 7&#45;&gt;5 -->\n",
       "<g id=\"edge12\" class=\"edge\">\n",
       "<title>7&#45;&gt;5</title>\n",
       "<path fill=\"none\" stroke=\"black\" d=\"M332.72,-179.36C357.6,-164.67 400.56,-139.31 428.88,-122.6\"/>\n",
       "<polygon fill=\"black\" stroke=\"black\" points=\"430.69,-125.6 437.52,-117.5 427.13,-119.57 430.69,-125.6\"/>\n",
       "<text text-anchor=\"middle\" x=\"402\" y=\"-144.8\" font-family=\"Times,serif\" font-size=\"14.00\">&quot;i&quot;</text>\n",
       "</g>\n",
       "<!-- 8 -->\n",
       "<g id=\"node9\" class=\"node\">\n",
       "<title>8</title>\n",
       "<ellipse fill=\"none\" stroke=\"black\" cx=\"344\" cy=\"-105\" rx=\"27\" ry=\"18\"/>\n",
       "<text text-anchor=\"middle\" x=\"344\" y=\"-101.3\" font-family=\"Times,serif\" font-size=\"14.00\">8</text>\n",
       "</g>\n",
       "<!-- 7&#45;&gt;8 -->\n",
       "<g id=\"edge21\" class=\"edge\">\n",
       "<title>7&#45;&gt;8</title>\n",
       "<path fill=\"none\" stroke=\"black\" d=\"M319.12,-174.21C323.5,-162.22 329.47,-145.85 334.46,-132.16\"/>\n",
       "<polygon fill=\"black\" stroke=\"black\" points=\"337.75,-133.35 337.89,-122.76 331.17,-130.95 337.75,-133.35\"/>\n",
       "<text text-anchor=\"middle\" x=\"339\" y=\"-144.8\" font-family=\"Times,serif\" font-size=\"14.00\">&quot;i&quot;</text>\n",
       "</g>\n",
       "<!-- 7&#45;&gt;9 -->\n",
       "<g id=\"edge18\" class=\"edge\">\n",
       "<title>7&#45;&gt;9</title>\n",
       "<path fill=\"none\" stroke=\"black\" d=\"M286.03,-193.4C244.08,-195.71 165.18,-207.36 138,-261 130.77,-275.27 134.89,-281.3 138,-297 142.76,-321.05 150.24,-325.1 159,-348 184.34,-414.25 211.49,-493.24 225.11,-533.53\"/>\n",
       "<polygon fill=\"black\" stroke=\"black\" points=\"221.84,-534.77 228.36,-543.13 228.47,-532.54 221.84,-534.77\"/>\n",
       "<text text-anchor=\"middle\" x=\"181.5\" y=\"-362.3\" font-family=\"Times,serif\" font-size=\"14.00\">&quot;f&quot;</text>\n",
       "</g>\n",
       "<!-- 4 -->\n",
       "<g id=\"node3\" class=\"node\">\n",
       "<title>4</title>\n",
       "<ellipse fill=\"none\" stroke=\"black\" cx=\"115\" cy=\"-420\" rx=\"27\" ry=\"18\"/>\n",
       "<text text-anchor=\"middle\" x=\"115\" y=\"-416.3\" font-family=\"Times,serif\" font-size=\"14.00\">4</text>\n",
       "</g>\n",
       "<!-- 4&#45;&gt;6 -->\n",
       "<g id=\"edge27\" class=\"edge\">\n",
       "<title>4&#45;&gt;6</title>\n",
       "<path fill=\"none\" stroke=\"black\" d=\"M113.99,-438.25C113.6,-452.83 114.13,-474.13 119,-492 134.22,-547.85 181.27,-598.91 210.26,-626.21\"/>\n",
       "<polygon fill=\"black\" stroke=\"black\" points=\"208.19,-629.06 217.91,-633.26 212.93,-623.91 208.19,-629.06\"/>\n",
       "<text text-anchor=\"middle\" x=\"176.5\" y=\"-557.3\" font-family=\"Times,serif\" font-size=\"14.00\">&quot;q&quot;</text>\n",
       "</g>\n",
       "<!-- 2 -->\n",
       "<g id=\"node5\" class=\"node\">\n",
       "<title>2</title>\n",
       "<ellipse fill=\"none\" stroke=\"black\" cx=\"174\" cy=\"-279\" rx=\"27\" ry=\"18\"/>\n",
       "<text text-anchor=\"middle\" x=\"174\" y=\"-275.3\" font-family=\"Times,serif\" font-size=\"14.00\">2</text>\n",
       "</g>\n",
       "<!-- 4&#45;&gt;2 -->\n",
       "<g id=\"edge9\" class=\"edge\">\n",
       "<title>4&#45;&gt;2</title>\n",
       "<path fill=\"none\" stroke=\"black\" d=\"M120.28,-402.13C124.98,-387.6 132.3,-366.17 140,-348 146.12,-333.57 153.88,-317.9 160.43,-305.24\"/>\n",
       "<polygon fill=\"black\" stroke=\"black\" points=\"163.62,-306.7 165.17,-296.22 157.42,-303.45 163.62,-306.7\"/>\n",
       "<text text-anchor=\"middle\" x=\"149.5\" y=\"-362.3\" font-family=\"Times,serif\" font-size=\"14.00\">&quot;e&quot;</text>\n",
       "</g>\n",
       "<!-- 4&#45;&gt;3 -->\n",
       "<g id=\"edge23\" class=\"edge\">\n",
       "<title>4&#45;&gt;3</title>\n",
       "<path fill=\"none\" stroke=\"black\" d=\"M105.25,-403.09C94.89,-384.64 80,-352.99 80,-323.5 80,-323.5 80,-323.5 80,-104 80,-81.61 91.69,-58.89 102.58,-42.59\"/>\n",
       "<polygon fill=\"black\" stroke=\"black\" points=\"105.57,-44.42 108.48,-34.23 99.85,-40.39 105.57,-44.42\"/>\n",
       "<text text-anchor=\"middle\" x=\"89.5\" y=\"-231.8\" font-family=\"Times,serif\" font-size=\"14.00\">&quot;q&quot;</text>\n",
       "</g>\n",
       "<!-- 5&#45;&gt;3 -->\n",
       "<g id=\"edge3\" class=\"edge\">\n",
       "<title>5&#45;&gt;3</title>\n",
       "<path fill=\"none\" stroke=\"black\" d=\"M432.02,-97.68C372.85,-82.71 224.04,-45.07 155.97,-27.85\"/>\n",
       "<polygon fill=\"black\" stroke=\"black\" points=\"156.7,-24.42 146.14,-25.36 154.98,-31.21 156.7,-24.42\"/>\n",
       "<text text-anchor=\"middle\" x=\"319.5\" y=\"-57.8\" font-family=\"Times,serif\" font-size=\"14.00\">&quot;p&quot;</text>\n",
       "</g>\n",
       "<!-- 2&#45;&gt;7 -->\n",
       "<g id=\"edge17\" class=\"edge\">\n",
       "<title>2&#45;&gt;7</title>\n",
       "<path fill=\"none\" stroke=\"black\" d=\"M178.33,-260.96C181.91,-250.11 188.06,-236.53 198,-228 219.89,-209.21 251.68,-200.5 276.29,-196.47\"/>\n",
       "<polygon fill=\"black\" stroke=\"black\" points=\"276.95,-199.92 286.34,-195.02 275.95,-192.99 276.95,-199.92\"/>\n",
       "<text text-anchor=\"middle\" x=\"206.5\" y=\"-231.8\" font-family=\"Times,serif\" font-size=\"14.00\">&quot;r&quot;</text>\n",
       "</g>\n",
       "<!-- 2&#45;&gt;3 -->\n",
       "<g id=\"edge5\" class=\"edge\">\n",
       "<title>2&#45;&gt;3</title>\n",
       "<path fill=\"none\" stroke=\"black\" d=\"M170.52,-261.01C161.54,-217.1 137.49,-99.6 126.56,-46.15\"/>\n",
       "<polygon fill=\"black\" stroke=\"black\" points=\"129.92,-45.15 124.49,-36.06 123.07,-46.55 129.92,-45.15\"/>\n",
       "<text text-anchor=\"middle\" x=\"157\" y=\"-144.8\" font-family=\"Times,serif\" font-size=\"14.00\">&quot;l&quot;</text>\n",
       "</g>\n",
       "<!-- 3&#45;&gt;6 -->\n",
       "<g id=\"edge11\" class=\"edge\">\n",
       "<title>3&#45;&gt;6</title>\n",
       "<path fill=\"none\" stroke=\"black\" d=\"M147.71,-20.84C249.18,-28.16 605,-57.18 605,-104 605,-562 605,-562 605,-562 605,-630 365.19,-643.6 271.18,-646.32\"/>\n",
       "<polygon fill=\"black\" stroke=\"black\" points=\"270.88,-642.83 260.98,-646.59 271.07,-649.82 270.88,-642.83\"/>\n",
       "<text text-anchor=\"middle\" x=\"614.5\" y=\"-318.8\" font-family=\"Times,serif\" font-size=\"14.00\">&quot;a&quot;</text>\n",
       "</g>\n",
       "<!-- 1 -->\n",
       "<g id=\"node7\" class=\"node\">\n",
       "<title>1</title>\n",
       "<ellipse fill=\"none\" stroke=\"black\" cx=\"356\" cy=\"-474\" rx=\"27\" ry=\"18\"/>\n",
       "<text text-anchor=\"middle\" x=\"356\" y=\"-470.3\" font-family=\"Times,serif\" font-size=\"14.00\">1</text>\n",
       "</g>\n",
       "<!-- 1&#45;&gt;6 -->\n",
       "<g id=\"edge25\" class=\"edge\">\n",
       "<title>1&#45;&gt;6</title>\n",
       "<path fill=\"none\" stroke=\"black\" d=\"M352.82,-491.92C350.49,-501.96 346.71,-514.69 341,-525 318.81,-565.08 281.63,-603.47 257.47,-626.14\"/>\n",
       "<polygon fill=\"black\" stroke=\"black\" points=\"254.78,-623.85 249.81,-633.21 259.53,-629 254.78,-623.85\"/>\n",
       "<text text-anchor=\"middle\" x=\"338.5\" y=\"-557.3\" font-family=\"Times,serif\" font-size=\"14.00\">&quot;r&quot;</text>\n",
       "</g>\n",
       "<!-- 10 -->\n",
       "<g id=\"node8\" class=\"node\">\n",
       "<title>10</title>\n",
       "<ellipse fill=\"none\" stroke=\"black\" cx=\"368\" cy=\"-366\" rx=\"27\" ry=\"18\"/>\n",
       "<text text-anchor=\"middle\" x=\"368\" y=\"-362.3\" font-family=\"Times,serif\" font-size=\"14.00\">10</text>\n",
       "</g>\n",
       "<!-- 1&#45;&gt;10 -->\n",
       "<g id=\"edge4\" class=\"edge\">\n",
       "<title>1&#45;&gt;10</title>\n",
       "<path fill=\"none\" stroke=\"black\" d=\"M358.59,-455.93C359.41,-450.23 360.29,-443.85 361,-438 362.73,-423.69 364.33,-407.71 365.57,-394.54\"/>\n",
       "<polygon fill=\"black\" stroke=\"black\" points=\"369.08,-394.52 366.51,-384.24 362.11,-393.88 369.08,-394.52\"/>\n",
       "<text text-anchor=\"middle\" x=\"374.5\" y=\"-416.3\" font-family=\"Times,serif\" font-size=\"14.00\">&quot;u&quot;</text>\n",
       "</g>\n",
       "<!-- 1&#45;&gt;8 -->\n",
       "<g id=\"edge16\" class=\"edge\">\n",
       "<title>1&#45;&gt;8</title>\n",
       "<path fill=\"none\" stroke=\"black\" d=\"M371.6,-458.82C377.41,-452.87 383.65,-445.57 388,-438 436.45,-353.75 467.47,-323.42 449,-228 441.08,-187.08 442.25,-171.64 414,-141 404.17,-130.33 390.36,-122.48 377.6,-116.94\"/>\n",
       "<polygon fill=\"black\" stroke=\"black\" points=\"378.72,-113.62 368.13,-113.15 376.12,-120.12 378.72,-113.62\"/>\n",
       "<text text-anchor=\"middle\" x=\"462.5\" y=\"-275.3\" font-family=\"Times,serif\" font-size=\"14.00\">&quot;r&quot;</text>\n",
       "</g>\n",
       "<!-- 10&#45;&gt;7 -->\n",
       "<g id=\"edge1\" class=\"edge\">\n",
       "<title>10&#45;&gt;7</title>\n",
       "<path fill=\"none\" stroke=\"black\" d=\"M363.43,-347.97C356.33,-321.91 341.88,-270.66 327,-228 325.98,-225.07 324.85,-222.02 323.7,-219\"/>\n",
       "<polygon fill=\"black\" stroke=\"black\" points=\"326.92,-217.64 320,-209.62 320.41,-220.21 326.92,-217.64\"/>\n",
       "<text text-anchor=\"middle\" x=\"357\" y=\"-275.3\" font-family=\"Times,serif\" font-size=\"14.00\">&quot;t&quot;</text>\n",
       "</g>\n",
       "<!-- 10&#45;&gt;7 -->\n",
       "<g id=\"edge10\" class=\"edge\">\n",
       "<title>10&#45;&gt;7</title>\n",
       "<path fill=\"none\" stroke=\"black\" d=\"M371.69,-347.84C375.44,-326.71 379.37,-290.08 369,-261 362.49,-242.75 348.71,-225.91 336.44,-213.55\"/>\n",
       "<polygon fill=\"black\" stroke=\"black\" points=\"338.71,-210.88 329.08,-206.46 333.86,-215.92 338.71,-210.88\"/>\n",
       "<text text-anchor=\"middle\" x=\"385.5\" y=\"-275.3\" font-family=\"Times,serif\" font-size=\"14.00\">&quot;g&quot;</text>\n",
       "</g>\n",
       "<!-- 10&#45;&gt;7 -->\n",
       "<g id=\"edge15\" class=\"edge\">\n",
       "<title>10&#45;&gt;7</title>\n",
       "<path fill=\"none\" stroke=\"black\" d=\"M352.63,-351.07C339.86,-338.4 322.6,-318.44 315,-297 306.17,-272.1 306.78,-241.7 308.92,-220.21\"/>\n",
       "<polygon fill=\"black\" stroke=\"black\" points=\"312.41,-220.5 310.1,-210.16 305.46,-219.68 312.41,-220.5\"/>\n",
       "<text text-anchor=\"middle\" x=\"324.5\" y=\"-275.3\" font-family=\"Times,serif\" font-size=\"14.00\">&quot;q&quot;</text>\n",
       "</g>\n",
       "<!-- 10&#45;&gt;5 -->\n",
       "<g id=\"edge7\" class=\"edge\">\n",
       "<title>10&#45;&gt;5</title>\n",
       "<path fill=\"none\" stroke=\"black\" d=\"M378.69,-349.07C382.29,-343.23 386.13,-336.48 389,-330 419.31,-261.68 441.17,-175.91 451.07,-133.03\"/>\n",
       "<polygon fill=\"black\" stroke=\"black\" points=\"454.53,-133.61 453.33,-123.09 447.7,-132.06 454.53,-133.61\"/>\n",
       "<text text-anchor=\"middle\" x=\"435.5\" y=\"-231.8\" font-family=\"Times,serif\" font-size=\"14.00\">&quot;g&quot;</text>\n",
       "</g>\n",
       "<!-- 10&#45;&gt;2 -->\n",
       "<g id=\"edge20\" class=\"edge\">\n",
       "<title>10&#45;&gt;2</title>\n",
       "<path fill=\"none\" stroke=\"black\" d=\"M345.17,-355.88C328,-348.96 303.93,-339.1 283,-330 256.39,-318.42 226.45,-304.63 204.69,-294.47\"/>\n",
       "<polygon fill=\"black\" stroke=\"black\" points=\"206.14,-291.29 195.6,-290.21 203.17,-297.62 206.14,-291.29\"/>\n",
       "<text text-anchor=\"middle\" x=\"291.5\" y=\"-318.8\" font-family=\"Times,serif\" font-size=\"14.00\">&quot;r&quot;</text>\n",
       "</g>\n",
       "<!-- 10&#45;&gt;1 -->\n",
       "<g id=\"edge6\" class=\"edge\">\n",
       "<title>10&#45;&gt;1</title>\n",
       "<path fill=\"none\" stroke=\"black\" d=\"M352.2,-380.77C346.59,-386.68 340.94,-394.04 338,-402 332.45,-417.01 334.24,-422.45 338,-438 338.83,-441.42 340.05,-444.89 341.48,-448.24\"/>\n",
       "<polygon fill=\"black\" stroke=\"black\" points=\"338.35,-449.8 345.88,-457.25 344.64,-446.73 338.35,-449.8\"/>\n",
       "<text text-anchor=\"middle\" x=\"347.5\" y=\"-416.3\" font-family=\"Times,serif\" font-size=\"14.00\">&quot;g&quot;</text>\n",
       "</g>\n",
       "<!-- 9&#45;&gt;7 -->\n",
       "<g id=\"edge8\" class=\"edge\">\n",
       "<title>9&#45;&gt;7</title>\n",
       "<path fill=\"none\" stroke=\"black\" d=\"M241.37,-543.5C243.73,-537.73 246.21,-531.16 248,-525 285.56,-396.03 274.81,-359.12 304,-228 304.59,-225.34 305.24,-222.57 305.92,-219.8\"/>\n",
       "<polygon fill=\"black\" stroke=\"black\" points=\"309.33,-220.59 308.38,-210.04 302.54,-218.88 309.33,-220.59\"/>\n",
       "<text text-anchor=\"middle\" x=\"292.5\" y=\"-362.3\" font-family=\"Times,serif\" font-size=\"14.00\">&quot;g&quot;</text>\n",
       "</g>\n",
       "<!-- 9&#45;&gt;7 -->\n",
       "<g id=\"edge14\" class=\"edge\">\n",
       "<title>9&#45;&gt;7</title>\n",
       "<path fill=\"none\" stroke=\"black\" d=\"M232.25,-542.94C228.65,-502.46 222.59,-397.78 246,-315 256.38,-278.3 279.43,-240.48 295.58,-216.87\"/>\n",
       "<polygon fill=\"black\" stroke=\"black\" points=\"298.53,-218.75 301.39,-208.55 292.79,-214.74 298.53,-218.75\"/>\n",
       "<text text-anchor=\"middle\" x=\"248.5\" y=\"-362.3\" font-family=\"Times,serif\" font-size=\"14.00\">&quot;q&quot;</text>\n",
       "</g>\n",
       "<!-- 9&#45;&gt;4 -->\n",
       "<g id=\"edge26\" class=\"edge\">\n",
       "<title>9&#45;&gt;4</title>\n",
       "<path fill=\"none\" stroke=\"black\" d=\"M208.06,-555.56C188.99,-550.99 163.75,-542.05 148,-525 137.56,-513.7 127.08,-474.87 120.82,-447.99\"/>\n",
       "<polygon fill=\"black\" stroke=\"black\" points=\"124.18,-446.99 118.56,-438.01 117.35,-448.54 124.18,-446.99\"/>\n",
       "<text text-anchor=\"middle\" x=\"157.5\" y=\"-513.8\" font-family=\"Times,serif\" font-size=\"14.00\">&quot;p&quot;</text>\n",
       "</g>\n",
       "<!-- 9&#45;&gt;1 -->\n",
       "<g id=\"edge13\" class=\"edge\">\n",
       "<title>9&#45;&gt;1</title>\n",
       "<path fill=\"none\" stroke=\"black\" d=\"M255.87,-550.06C269.1,-543.65 286.06,-534.71 300,-525 311.98,-516.66 324.21,-506.04 334.16,-496.73\"/>\n",
       "<polygon fill=\"black\" stroke=\"black\" points=\"336.79,-499.06 341.61,-489.62 331.96,-494 336.79,-499.06\"/>\n",
       "<text text-anchor=\"middle\" x=\"327.5\" y=\"-513.8\" font-family=\"Times,serif\" font-size=\"14.00\">&quot;a&quot;</text>\n",
       "</g>\n",
       "</g>\n",
       "</svg>\n"
      ],
      "text/plain": [
       "<graphviz.graphs.Digraph at 0x110a60790>"
      ]
     },
     "execution_count": 8,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "#answers_table = pa.Table.from_pandas(answers)\n",
    "try:\n",
    "    import graphviz\n",
    "    from IPython.display import Image\n",
    "    \n",
    "    gr = graphviz.Digraph()\n",
    "    # Draw nodes for the union of all source and target nodes in the two paths\n",
    "    for node in set(answers.column('a')) | set(answers.column('c')):\n",
    "        gr.node(str(node))\n",
    "    # Draw edges for each returned edge\n",
    "    for batch in answers.to_batches():\n",
    "        d = batch.to_pydict()\n",
    "        for a, c, attr1 in zip(d['a'], d['c'], d['attr1']):\n",
    "            # Do something with the row\n",
    "            gr.edge(str(a), str(c), label=f'\"{str(attr1)}\"')\n",
    "\n",
    "except ImportError:\n",
    "    print(\"You must install graphviz in order to vizualize the results as a graph\")\n",
    "    print(\"\\n!python3 -m pip install graphviz\")\n",
    "    gr = None\n",
    "\n",
    "gr"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "4b7eb72c",
   "metadata": {},
   "source": [
    "<footer>&copy; 2016-2026 Trovares Inc. dba Rocketgraph.  All rights reserved.</footer>"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.13.2"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
