Skip to content

Commit

Permalink
utilities: add output_graph_image
Browse files Browse the repository at this point in the history
Writes an image representation of a graph to a file. Several
common formats supported.
  • Loading branch information
kmantel committed Dec 8, 2023
1 parent 7fdbd0d commit 79c0135
Show file tree
Hide file tree
Showing 4 changed files with 71 additions and 2 deletions.
3 changes: 3 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,9 @@ jobs:
if: ${{ matrix.python-version == 3.9 }}
run: python -m pip install coveragepy-lcov "coverage<7.0.0"

- name: Install Graphviz
uses: tlylt/install-graphviz@v1

- name: Lint with flake8
shell: bash
run: |
Expand Down
1 change: 1 addition & 0 deletions dev_requirements.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
psyneulink >=0.9.1.0
pydot
pytest
pytest-benchmark
pytest-cov
Expand Down
58 changes: 56 additions & 2 deletions src/graph_scheduler/utilities.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,14 @@
import inspect
import logging
import weakref
from typing import Dict, Hashable, Set
from typing import Dict, Hashable, Set, Union

import networkx as nx

__all__ = [
'clone_graph', 'dependency_dict_to_networkx_digraph',
'disable_debug_logging', 'enable_debug_logging',
'networkx_digraph_to_dependency_dict',
'networkx_digraph_to_dependency_dict', 'output_graph_image',
]


Expand Down Expand Up @@ -199,3 +199,57 @@ def networkx_digraph_to_dependency_dict(
res_graph[rec] = set()
res_graph[rec].add(sender)
return res_graph


def output_graph_image(
graph: Union[typing_graph_dependency_dict, nx.Graph],
filename: str = None,
format: str = 'png',
):
"""
Writes an image representation of **graph** to file **filename**.
Args:
graph: a graph in dependency dict form
filename (str, optional): full path of image to write. Defaults
to 'graph-scheduler-figure-<graph id>.<format>' in the current
directory.
format (str, optional): image format. Many common formats
supported. Pass None to display supported formats. Defaults
to png.
Requires:
- system graphviz: https://graphviz.org/download
- Python pydot: pip install pydot
"""
if filename is None:
filename = f'graph-scheduler-figure-{id(graph)}.{format}'

if not isinstance(graph, nx.Graph):
graph = dependency_dict_to_networkx_digraph(graph)

try:
pd = nx.drawing.nx_pydot.to_pydot(graph)
except ModuleNotFoundError as e:
raise ModuleNotFoundError(
'Python pydot is required for output_graph_image.'
' Install it with: pip install pydot'
) from e

try:
pd.write(filename, format=format)
except AssertionError as e:
raise AssertionError(
f"Format '{format}' not recognized. Supported formats:"
f" {', '.join(pd.formats)}"
) from e
except FileNotFoundError as e:
if '"dot" not found in path' in str(e):
raise FileNotFoundError(
'System graphviz is required for output_graph_image.'
' Install it from https://graphviz.org/download'
) from e
else:
raise

print(f'graph_scheduler.output_graph_image: wrote {format} to {filename}')
11 changes: 11 additions & 0 deletions tests/test_utilities.py
Original file line number Diff line number Diff line change
Expand Up @@ -115,3 +115,14 @@ def test_convert_from_nx_graph(graph, nx_type):
)
assert nx_graph.nodes == nx_graph.nodes
assert nx_graph.edges == res.edges


@pytest.mark.parametrize('graph', test_graphs)
@pytest.mark.parametrize('nx_type', nx_digraph_types)
@pytest.mark.parametrize('format', ['png', 'jpg', 'svg'])
def test_output_graph_image(graph, nx_type, format, tmp_path):
fname = f'{tmp_path}_fig.{format}'
nx_graph = graph_as_nx_graph(graph, nx_type)

gs.output_graph_image(graph, fname, format)
gs.output_graph_image(nx_graph, fname, format)

0 comments on commit 79c0135

Please sign in to comment.