Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
617e577
FIX(build): py2 needs pinning networkx-2.2
ankostis Sep 28, 2019
f58d148
FIX(#13): BUG in plot-diagram writtin from PY2 era,
ankostis Sep 29, 2019
c75a2c0
doc(#13): sample code to plot workflow diagram in intro
ankostis Sep 29, 2019
a005bd6
enh(plot): provide help msg on supported file-exts
ankostis Sep 29, 2019
32409f6
enh(build): replace numpy with pytest...
ankostis Oct 3, 2019
f606ed1
feat(build): add pip-extras [test]
ankostis Oct 3, 2019
cd1370b
TEST(plot,ci): test plotting; pip install extras in Travis
ankostis Sep 29, 2019
f676662
fix(plot): don't create file on unsupported formats
ankostis Sep 29, 2019
65d1816
enh(plot.TC): expose supported writers and TC on them
ankostis Sep 29, 2019
4e55b30
enh(build,ci): use pytest in travis
ankostis Oct 3, 2019
47b50f6
fix(plot): NetOp did not return pydot instance
ankostis Oct 4, 2019
b1d02a1
refact(plot): extract plot function out of Network class...
ankostis Oct 4, 2019
c11af2a
fix(plot): matplotlib plot was failing in PY3 due IO io misuse
ankostis Oct 4, 2019
344490b
FEAT(plot): overlay Execution STEPS on diagrams
ankostis Oct 5, 2019
23ef81e
ENH(plot): +inputs, +outputs, +solution modify plotting
ankostis Oct 5, 2019
4e8601c
refact(plot.TC): move plot tests to early beggining
ankostis Oct 5, 2019
834a8b0
doc(plot): tell supported formats in doctest, +TC
ankostis Oct 5, 2019
c2e28a4
doc(plot): add legend & example; docstring in netop.plot()
ankostis Oct 5, 2019
e38c8ad
enh(plot): mark optional "needs"
ankostis Oct 5, 2019
d855bf6
ENH(plot): visual enhamcents on nodes & edges
ankostis Oct 5, 2019
ca5d243
test(plot): enhance plot test to try all #13 features;
ankostis Oct 5, 2019
a2de9ef
doc(plot); explain also params in user-facing API
ankostis Oct 5, 2019
dc5a21a
FIX(PLOT.TC): TC was always testing PNG, ...
ankostis Oct 5, 2019
782d9b9
fix(plot): don't require Matplotlib if no Window asked
ankostis Oct 5, 2019
7d389c3
test(plot): check also matplotlib show=True
ankostis Oct 5, 2019
3fe0b40
ENH(plot): return SVG rendered in JUPYTER, ...
ankostis Oct 5, 2019
1471551
refact(plot.TC): avoid writting multiple temp-files
ankostis Oct 5, 2019
af7ae0f
MERGE PYTEST into PLOT to parametrize TCs.
ankostis Oct 5, 2019
b440196
fix(build): reuse dependencies definitions
ankostis Oct 5, 2019
bde9b64
REFACT(plot.TC): PYTESTize and parametrize
ankostis Oct 5, 2019
8e361e6
REFACT(PLOT): MOVE PLOT in own module
ankostis Oct 5, 2019
b08a363
DROP PY3.4 - add PY3.6, PY3.7...
ankostis Oct 5, 2019
3a87959
refact(plot): separate graphviz building from IO
ankostis Oct 5, 2019
4aca013
FIX(plot): failing if steps not a list/ is none...
ankostis Oct 6, 2019
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 10 additions & 3 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,26 @@ language: python

python:
- "2.7"
- "3.4"
- "3.5"
- "3.6"
- "3.7"

addons:
apt:
packages:
- graphviz


install:
- pip install Sphinx sphinx_rtd_theme codecov packaging
- "python -c $'import os, packaging.version as version\\nv = version.parse(os.environ.get(\"TRAVIS_TAG\", \"1.0\")).public\\nwith open(\"VERSION\", \"w\") as f: f.write(v)'"
- python setup.py install
- pip install -e .[test]
- cd docs
- make clean html
- cd ..

script:
- python setup.py nosetests --with-coverage --cover-package=graphkit
- pytest -v --cov=graphkit

deploy:
provider: pypi
Expand Down
13 changes: 13 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,19 @@ print(out)

As you can see, any function can be used as an operation in GraphKit, even ones imported from system modules!

For debugging, you may plot the workflow with one of these methods:

```python
graph.net.plot(show=True) # open a matplotlib window
graph.net.plot("path/to/workflow.png") # supported files: .png .dot .jpg .jpeg .pdf .svg
```

> **NOTE**: For plots, `graphviz` must be in your PATH, and `pydot` & `matplotlib` python packages installed.
> You may install both when installing *graphkit* with its `plot` extras:
> ```python
> pip install graphkit[plot]
> ```

# License

Code licensed under the Apache License, Version 2.0 license. See LICENSE file for terms.
12 changes: 12 additions & 0 deletions docs/source/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,18 @@ Here's a Python script with an example GraphKit computation graph that produces

As you can see, any function can be used as an operation in GraphKit, even ones imported from system modules!

For debugging, you may plot the workflow with one of these methods::

graph.net.plot(show=True) # open a matplotlib window
graph.net.plot("path/to/workflow.png") # supported files: .png .dot .jpg .jpeg .pdf .svg

.. NOTE::
For plots, ``graphviz`` must be in your PATH, and ``pydot` & ``matplotlib`` python packages installed.
You may install both when installing *graphkit* with its `plot` extras::

pip install graphkit[plot]


License
-------

Expand Down
31 changes: 29 additions & 2 deletions graphkit/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -171,8 +171,35 @@ def set_execution_method(self, method):
assert method in options
self._execution_method = method

def plot(self, filename=None, show=False):
self.net.plot(filename=filename, show=show)
def plot(self, filename=None, show=False, jupyter=None,
inputs=None, outputs=None, solution=None):
"""
:param str filename:
Write diagram into a file.
Common extensions are ``.png .dot .jpg .jpeg .pdf .svg``
call :func:`plot.supported_plot_formats()` for more.
:param show:
If it evaluates to true, opens the diagram in a matplotlib window.
If it equals `-1`, it plots but does not open the Window.
:param jupyter:
If it evaluates to true, return an SVG suitable to render
in *jupyter notebook cells* (`ipython` must be installed).
:param inputs:
an optional name list, any nodes in there are plotted
as a "house"
:param outputs:
an optional name list, any nodes in there are plotted
as an "inverted-house"
:param solution:
an optional dict with values to annotate nodes
(currently content not shown, but node drawn as "filled")

:return:
An instance of the :mod`pydot` graph

See :func:`graphkit.plot.plot_graph()` for the plot legend and example code.
"""
return self.net.plot(filename, show, jupyter, inputs, outputs, solution)

def __getstate__(self):
state = Operation.__getstate__(self)
Expand Down
107 changes: 38 additions & 69 deletions graphkit/network.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,11 @@
# Licensed under the terms of the Apache License, Version 2.0. See the LICENSE file associated with the project for terms.

import time
import os
import networkx as nx

from io import StringIO

from .base import Operation
from .modifiers import optional


class DataPlaceholderNode(str):
Expand Down Expand Up @@ -375,77 +374,40 @@ def _compute_sequential_method(self, named_inputs, outputs):
return {k: cache[k] for k in iter(cache) if k in outputs}


def plot(self, filename=None, show=False):
def plot(self, filename=None, show=False, jupyter=None,
inputs=None, outputs=None, solution=None):
"""
Plot the graph.
Plot a *Graphviz* graph and return it, if no other argument provided.

params:
:param str filename:
Write the output to a png, pdf, or graphviz dot file. The extension
controls the output format.

:param boolean show:
If this is set to True, use matplotlib to show the graph diagram
(Default: False)

:returns:
An instance of the pydot graph

Write diagram into a file.
Common extensions are ``.png .dot .jpg .jpeg .pdf .svg``
call :func:`plot.supported_plot_formats()` for more.
:param show:
If it evaluates to true, opens the diagram in a matplotlib window.
If it equals `-1``, it plots but does not open the Window.
:param jupyter:
If it evaluates to true, return an SVG suitable to render
in *jupyter notebook cells* (`ipython` must be installed).
:param inputs:
an optional name list, any nodes in there are plotted
as a "house"
:param outputs:
an optional name list, any nodes in there are plotted
as an "inverted-house"
:param solution:
an optional dict with values to annotate nodes
(currently content not shown, but node drawn as "filled")

:return:
An instance of the :mod`pydot` graph

See :func:`graphkit.plot.plot_graph()` for the plot legend and example code.
"""
import pydot
import matplotlib.pyplot as plt
import matplotlib.image as mpimg

assert self.graph is not None

def get_node_name(a):
if isinstance(a, DataPlaceholderNode):
return a
return a.name

g = pydot.Dot(graph_type="digraph")

# draw nodes
for nx_node in self.graph.nodes():
if isinstance(nx_node, DataPlaceholderNode):
node = pydot.Node(name=nx_node, shape="rect")
else:
node = pydot.Node(name=nx_node.name, shape="circle")
g.add_node(node)

# draw edges
for src, dst in self.graph.edges():
src_name = get_node_name(src)
dst_name = get_node_name(dst)
edge = pydot.Edge(src=src_name, dst=dst_name)
g.add_edge(edge)

# save plot
if filename:
basename, ext = os.path.splitext(filename)
with open(filename, "w") as fh:
if ext.lower() == ".png":
fh.write(g.create_png())
elif ext.lower() == ".dot":
fh.write(g.to_string())
elif ext.lower() in [".jpg", ".jpeg"]:
fh.write(g.create_jpeg())
elif ext.lower() == ".pdf":
fh.write(g.create_pdf())
elif ext.lower() == ".svg":
fh.write(g.create_svg())
else:
raise Exception("Unknown file format for saving graph: %s" % ext)

# display graph via matplotlib
if show:
png = g.create_png()
sio = StringIO(png)
img = mpimg.imread(sio)
plt.imshow(img, aspect="equal")
plt.show()

return g
from . import plot

return plot.plot_graph(self.graph, filename, show, jupyter,
self.steps, inputs, outputs, solution)


def ready_to_schedule_operation(op, has_executed, graph):
Expand Down Expand Up @@ -494,3 +456,10 @@ def get_data_node(name, graph):
if node == name and isinstance(node, DataPlaceholderNode):
return node
return None


def supported_plot_formats():
"""return automatically all `pydot` extensions withlike ``.png``"""
import pydot

return [".%s" % f for f in pydot.Dot().formats]
Loading