|
| 1 | +ogdf-python: Automagic Python Bindings for the Open Graph Drawing Framework |
| 2 | +=========================================================================== |
| 3 | + |
| 4 | +`Original repository <https://github.com/N-Coder/ogdf-python>`_ (GitHub) - |
| 5 | +`Bugtracker and issues <https://github.com/N-Coder/ogdf-python>`_ (GitHub) - |
| 6 | +`PyPi package <https://pypi.python.org/pypi/ogdf-python>`_ (PyPi ``ogdf-python``) - |
| 7 | +`Documentation <https://ogdf-python.readthedocs.io>`_ (Read The Docs). |
| 8 | + |
| 9 | +`Official OGDF website <https://ogdf.net>`_ (ogdf.net) - |
| 10 | +`Public OGDF repository <https://github.com/ogdf/ogdf>`_ (GitHub) - |
| 11 | +`Internal OGDF repository <https://git.tcs.uos.de/ogdf-devs/OGDF>`_ (GitLab) - |
| 12 | +`OGDF Documentation <https://ogdf.github.io/docs/ogdf/>`_ (GitHub / Doxygen) - |
| 13 | +`cppyy Documentation <https://cppyy.readthedocs.io>`_ (Read The Docs). |
| 14 | + |
| 15 | +.. |(TM)| unicode:: U+2122 |
| 16 | + |
| 17 | +``ogdf-python`` uses the `black magic <http://www.camillescott.org/2019/04/11/cmake-cppyy/>`_ |
| 18 | +of the awesome `cppyy <https://bitbucket.org/wlav/cppyy/src/master/>`_ library to automagically generate python bindings |
| 19 | +for the C++ Open Graph Drawing Framework (OGDF). |
| 20 | +It is available for Python>=3.6 and is Apache2 licensed. |
| 21 | +There are no binding definitions files, no stuff that needs extra compiling, it just works\ |(TM)|, believe me. |
| 22 | +Templates, namespaces, cross-language callbacks and inheritance, pythonic iterators and generators, it's all there. |
| 23 | +If you want to learn more about the magic behind the curtains, read `this article <http://www.camillescott.org/2019/04/11/cmake-cppyy/>`_. |
| 24 | + |
| 25 | + |
| 26 | +Quickstart |
| 27 | +---------- |
| 28 | + |
| 29 | +First, install the package ``ogdf-python`` package. |
| 30 | +Please note that building ``cppyy`` from sources may take a while. |
| 31 | +If you didn't install OGDF globally on your system, |
| 32 | +either set the ``OGDF_INSTALL_DIR`` to the prefix you configured in ``cmake``, |
| 33 | +or set ``OGDF_BUILD_DIR`` to the subdirectory of your copy of the OGDF repo where your |
| 34 | +`out-of-source build <https://ogdf.github.io/docs/ogdf/md_doc_build.html#autotoc_md4>`_ lives. |
| 35 | + |
| 36 | +.. code-block:: bash |
| 37 | +
|
| 38 | + $ pip install ogdf-python |
| 39 | + $ OGDF_BUILD_DIR=~/ogdf/build-debug python3 |
| 40 | +
|
| 41 | +Alternatively, ``ogdf-python`` works very well with Jupyter: |
| 42 | + |
| 43 | +.. code-block:: python |
| 44 | +
|
| 45 | + %env OGDF_BUILD_DIR=~/ogdf/build-debug |
| 46 | +
|
| 47 | + from ogdf_python import ogdf, cppinclude |
| 48 | + cppinclude("ogdf/basic/graph_generators/randomized.h") |
| 49 | + cppinclude("ogdf/layered/SugiyamaLayout.h") |
| 50 | +
|
| 51 | + G = ogdf.Graph() |
| 52 | + ogdf.setSeed(1) |
| 53 | + ogdf.randomPlanarTriconnectedGraph(G, 20, 40) |
| 54 | + GA = ogdf.GraphAttributes(G, ogdf.GraphAttributes.all) |
| 55 | +
|
| 56 | + for n in G.nodes: |
| 57 | + GA.label[n] = "N%s" % n.index() |
| 58 | +
|
| 59 | + SL = ogdf.SugiyamaLayout() |
| 60 | + SL.call(GA) |
| 61 | + GA |
| 62 | +
|
| 63 | +.. image:: docs/examples/sugiyama-simple.svg |
| 64 | + :target: docs/examples/sugiyama-simple.ipynb |
| 65 | + :alt: SugiyamaLayouted Graph |
| 66 | + :height: 300 px |
| 67 | + |
| 68 | +Read the pitfalls section and check out `docs/examples/pitfalls.ipynb <docs/examples/pitfalls.ipynb>`_ |
| 69 | +for the more advanced Sugiyama example from the OGDF docs. |
| 70 | +There is also a bigger example in `docs/examples/ogdf-includes.ipynb <docs/examples/ogdf-includes.ipynb>`_. |
| 71 | +If anything is unclear, check out the python help ``help(ogdf.Graph)`` and read the corresponding OGDF documentation. |
| 72 | + |
| 73 | +.. |
| 74 | + Documentation |
| 75 | + ------------- |
| 76 | + TODO use ``help(ogdf.Graph)`` and sphinx autodoc |
| 77 | +
|
| 78 | +.. |
| 79 | + Load Custom Code |
| 80 | + ---------------- |
| 81 | + TODO |
| 82 | +
|
| 83 | +Pitfalls |
| 84 | +-------- |
| 85 | + |
| 86 | +See also `docs/examples/pitfalls.ipynb <docs/examples/pitfalls.ipynb>`_ for full examples. |
| 87 | + |
| 88 | +OGDF sometimes takes ownership of objects (usually when they are passed as modules), |
| 89 | +which may conflict with the automatic cppyy garbage collection. |
| 90 | +Set ``__python_owns__ = False`` on those objects to tell cppyy that those objects |
| 91 | +don't need to be garbage collected, but will be cleaned up from the C++ side. |
| 92 | + |
| 93 | +.. code-block:: python |
| 94 | +
|
| 95 | + SL = ogdf.SugiyamaLayout() |
| 96 | + ohl = ogdf.OptimalHierarchyLayout() |
| 97 | + ohl.__python_owns__ = False |
| 98 | + SL.setLayout(ohl) |
| 99 | +
|
| 100 | +When you overwrite a python variable pointing to a C++ object (and it is the only |
| 101 | +python variable pointing to that object), the C++ will usually be immediately deleted. |
| 102 | +This might be a problem if another C++ objects depends ob that old object, e.g. |
| 103 | +a ``GraphAttributes`` instance depending on a ``Graph`` instance. |
| 104 | +Now the other C++ object has a pointer to a delted and now invalid location, |
| 105 | +which will usually cause issues down the road (e.g. when the dependant object is |
| 106 | +deleted and wants to deregister from its no longer alive parent). |
| 107 | +This overwriting might easily happen if you run a Jupyter cell multiple times. |
| 108 | +Please ensure that you always overwrite or delete C++ dependent variables in |
| 109 | +the reverse order of their initialization. |
| 110 | + |
| 111 | +.. code-block:: python |
| 112 | +
|
| 113 | + CGA = CG = G = None |
| 114 | + G = ogdf.Graph() |
| 115 | + CG = ogdf.ClusterGraph(G) |
| 116 | + CGA = ogdf.ClusterGraphAttributes(CG, ogdf.ClusterGraphAttributes.all) |
| 117 | +
|
0 commit comments