Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PR: Replace pygraphviz with pydot. #1298

Merged
merged 1 commit into from
Oct 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ jobs:
if: matrix.os == 'macOS-latest'
run: |
poetry run python -m pip install --upgrade pip
poetry install --without graphviz
poetry install
- name: Install Package Dependencies (Ubuntu)
if: matrix.os == 'ubuntu-latest'
run: |
Expand All @@ -63,7 +63,7 @@ jobs:
if: matrix.os == 'windows-latest'
run: |
poetry run python -m pip install --upgrade pip
poetry install --without graphviz
poetry install
poetry run python -c "import imageio;imageio.plugins.freeimage.download()"
shell: bash
- name: Install OpenImageIO (macOs)
Expand Down
74 changes: 41 additions & 33 deletions colour/plotting/graph.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@

from __future__ import annotations

import os

import colour
from colour.graph import (
CONVERSION_GRAPH_NODE_LABELS,
Expand All @@ -29,13 +31,12 @@
]


@required("Graphviz")
@required("Pydot")
@required("NetworkX")
def plot_automatic_colour_conversion_graph(
filename: str,
prog: (Literal["circo", "dot", "fdp", "neato", "nop", "twopi"] | str) = "fdp",
args: str = "",
) -> AGraph: # pyright: ignore # noqa: F821 # pragma: no cover
prog: Literal["circo", "dot", "fdp", "neato", "nop", "twopi"] | str = "fdp",
) -> Dot: # pyright: ignore # noqa: F821 # pragma: no cover
"""
Plot *Colour* automatic colour conversion graph using
`Graphviz <https://www.graphviz.org>`__ and
Expand All @@ -47,13 +48,11 @@ def plot_automatic_colour_conversion_graph(
Filename to use to save the image.
prog
*Graphviz* layout method.
args
Additional arguments for *Graphviz*.

Returns
-------
:class:`AGraph`
*Pyraphviz* graph.
:class:`pydot.Dot`
*Pydot* graph.

Notes
-----
Expand Down Expand Up @@ -87,28 +86,31 @@ def plot_automatic_colour_conversion_graph(
# TODO: Investigate API to trigger the conversion graph build.
describe_conversion_path("RGB", "RGB", print_callable=lambda x: x)

agraph = nx.nx_agraph.to_agraph(cast(nx.DiGraph, colour.graph.CONVERSION_GRAPH))
dot = nx.drawing.nx_pydot.to_pydot(cast(nx.DiGraph, colour.graph.CONVERSION_GRAPH))

for node in agraph.nodes():
node.attr.update(label=CONVERSION_GRAPH_NODE_LABELS[node.name])
for node in dot.get_nodes():
label = CONVERSION_GRAPH_NODE_LABELS.get(node.get_name())

agraph.node_attr.update(
style="filled",
shape="circle",
color="#2196F3FF",
fillcolor="#2196F370",
fontname="Helvetica",
fontcolor="#263238",
)
agraph.edge_attr.update(color="#26323870")
for node in ("CIE XYZ", "RGB", "Spectral Distribution"):
agraph.get_node(node.lower()).attr.update(
shape="doublecircle",
color="#673AB7FF",
fillcolor="#673AB770",
fontsize=30,
)
for node in (
if label is None:
continue

node.set_label(label)
node.set_style("filled")
node.set_shape("circle")
node.set_color("#2196F3FF")
node.set_fillcolor("#2196F370")
node.set_fontname("Helvetica")
node.set_fontcolor("#263238")

for name in ("CIE XYZ", "RGB", "Spectral Distribution"):
node = next(iter(dot.get_node(name.lower())))

node.set_shape("doublecircle")
node.set_color("#673AB7FF")
node.set_fillcolor("#673AB770")
node.set_fontsize(30)

for name in (
"ATD95",
"CAM16",
"CIECAM02",
Expand All @@ -120,10 +122,16 @@ def plot_automatic_colour_conversion_graph(
"RLAB",
"ZCAM",
):
agraph.get_node(node.lower()).attr.update(
color="#00BCD4FF", fillcolor="#00BCD470"
)
node = next(iter(dot.get_node(name.lower())))

node.set_color("#00BCD4FF")
node.set_fillcolor("#00BCD470")

for edge in dot.get_edges():
edge.set_color("#26323870")

agraph.draw(filename, prog=prog, args=args)
file_format = os.path.splitext(filename)[-1][1:]
write_method = getattr(dot, f"write_{file_format}")
write_method(filename, prog=prog, f=file_format)

return agraph
return dot
6 changes: 2 additions & 4 deletions colour/plotting/tests/test_graph.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import tempfile

from colour.plotting import plot_automatic_colour_conversion_graph
from colour.utilities import is_graphviz_installed, is_networkx_installed
from colour.utilities import is_networkx_installed, is_pydot_installed

__author__ = "Colour Developers"
__copyright__ = "Copyright 2013 Colour Developers"
Expand All @@ -28,9 +28,7 @@ def test_plot_automatic_colour_conversion_graph(self):
plot_automatic_colour_conversion_graph` definition.
"""

if (
not is_graphviz_installed() or not is_networkx_installed()
): # pragma: no cover
if not is_pydot_installed() or not is_networkx_installed(): # pragma: no cover
return

plot_automatic_colour_conversion_graph( # pragma: no cover
Expand Down
4 changes: 2 additions & 2 deletions colour/utilities/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,12 +35,12 @@
)
from .requirements import (
is_ctlrender_installed,
is_graphviz_installed,
is_matplotlib_installed,
is_networkx_installed,
is_opencolorio_installed,
is_openimageio_installed,
is_pandas_installed,
is_pydot_installed,
is_tqdm_installed,
is_trimesh_installed,
is_xxhash_installed,
Expand Down Expand Up @@ -176,12 +176,12 @@
]
__all__ += [
"is_ctlrender_installed",
"is_graphviz_installed",
"is_matplotlib_installed",
"is_networkx_installed",
"is_opencolorio_installed",
"is_openimageio_installed",
"is_pandas_installed",
"is_pydot_installed",
"is_tqdm_installed",
"is_trimesh_installed",
"is_xxhash_installed",
Expand Down
45 changes: 25 additions & 20 deletions colour/utilities/network.py
Original file line number Diff line number Diff line change
Expand Up @@ -1919,16 +1919,15 @@ def process(self, **kwargs: Dict) -> None:

node.process()

@required("Graphviz")
def to_graphviz(self) -> AGraph: # noqa: F821 # pyright: ignore
@required("Pydot")
def to_graphviz(self) -> Dot: # noqa: F821 # pyright: ignore
"""
Return a visualisation node-graph for *Graphviz*.

Returns
-------
:class:`pygraphviz.AGraph`
String representation for visualisation of the node-graph with
*Graphviz*.
:class:`pydot.Dot`
*Pydot* graph.

Examples
--------
Expand All @@ -1941,17 +1940,17 @@ def to_graphviz(self) -> AGraph: # noqa: F821 # pyright: ignore
>>> graph.add_node(node_2)
>>> node_1.connect("output", node_2, "a")
>>> graph.to_graphviz() # doctest: +SKIP
<AGraph <Swig Object of type 'Agraph_t *' at 0x...>>
<pydot.core.Dot object at 0x...>
"""

if self._parent is not None:
return PortNode.to_graphviz(self)

from pygraphviz import AGraph
import pydot

agraph = AGraph(strict=False)
agraph.graph_attr["rankdir"] = "LR"
agraph.graph_attr["splines"] = "polyline"
dot = pydot.Dot(
"digraph", graph_type="digraph", rankdir="LR", splines="polyline"
)

graphs = [node for node in self.walk_ports() if isinstance(node, PortGraph)]

Expand All @@ -1961,8 +1960,12 @@ def is_graph_member(node: PortNode) -> bool:
return any(node in graph.nodes.values() for graph in graphs)

for node in self.walk_ports():
agraph.add_node(
f"{node.name} (#{node.id})", label=node.to_graphviz(), shape="record"
dot.add_node(
pydot.Node(
f"{node.name} (#{node.id})",
label=node.to_graphviz(),
shape="record",
)
)
input_edges, output_edges = node.edges

Expand All @@ -1971,16 +1974,18 @@ def is_graph_member(node: PortNode) -> bool:
if is_graph_member(edge[0].node) or is_graph_member(edge[1].node):
continue

agraph.add_edge(
f"{edge[1].node.name} (#{edge[1].node.id})",
f"{edge[0].node.name} (#{edge[0].node.id})",
tailport=edge[1].name,
headport=edge[0].name,
key=f"{edge[1]} => {edge[0]}",
dir="forward",
dot.add_edge(
pydot.Edge(
f"{edge[1].node.name} (#{edge[1].node.id})",
f"{edge[0].node.name} (#{edge[0].node.id})",
tailport=edge[1].name,
headport=edge[0].name,
key=f"{edge[1]} => {edge[0]}",
dir="forward",
)
)

return agraph
return dot


class ExecutionPort(Port):
Expand Down
Loading
Loading