Skip to content

Commit

Permalink
Replace pygraphviz plotting with pyvis (mckinsey#228)
Browse files Browse the repository at this point in the history
* initial draft for pyvis plotting

* modify edge length and mass for strong style and return pyvis object

* add pytests and fix sklearn plotting function

* update to include pyvis in requirements

* add in notebook check tests for test_plot_dag

* downgrade pyvis for compatibility

* update to latest plotting functions

* update requirements to exclude pygraphviz

* upgrading ipython

* moving ipython as main requirement

* simplify plot_structure function

* remove unused code and add test cases when needed

* reset pyvis version to see if .show() is working on v0.3.1

* set ipython and python versions

* undo previous change (ipython version change)

* remove ipython version from requirements

* re-add ipython version to requirements

* change ipython+python version

* undo change ipython+python version

* check for different ipython versions

* add quotation marks in requirements.txt

* revert back to ipython>=8.10.0

* try out ipython requirements from kedro

* revert back to ipython>=8.10

* change ipython requirements to successfully create environments

* Updated pyvis tutorials (mckinsey#232)

* update tutorials and adjust default values to improve output

* allow user to change layout in plot_dag function before calling .show()

* display df without dataframe_image

* fix dataframe_image No such file or directory

* remove one cell beacause unused

* incorporate windows solution from Kyle

* fix typo

* change plot_structure documentation

* change plot_dag documentation

* check and correct all notebooks

* remove python 3.6 and 3.7 support

* update documentation

* remove comment regarding ignoring a warning when running `make build-docs`

* removing ipython from test requiremnets

* refactoring plot syntax and changing logic in plot_dag

* addressing Gabriel's comments

* removing unused IPython conditional import

* refactoring code to use display

* Docs - update 01-tutorial

* updating first tutotiral

* updating plotting tutorial

* updating plotting tutorial

* updating display api

* fixing bug - displau

* fixing notebooks

* fixing notebooks

* fixing notebooks

* fixing notebooks

* Replacing Pygraphviz with Pyvis

* Replacing Pygraphviz with Pyvis

* Replacing Pygraphviz with Pyvis

* updating pyvis version

* updating notebook

* Richard Comments - batch 1

* Update tests/test_plotting.py

Co-authored-by: Richard Oentaryo <[email protected]>

* Update tests/test_plotting.py

Co-authored-by: Richard Oentaryo <[email protected]>

* Richard Comments - batch 2

* adjust node color test to include background color

* docs

* docs

* test

* fixing mdlp with cython

* fixing mdlp with cython

* test

* removing cython from requirements

* adding cython to config

---------

Co-authored-by: ElisabethSesterHussQB <[email protected]>
Co-authored-by: GabrielAz <[email protected]>
Co-authored-by: Gabriel Azevedo <[email protected]>
Co-authored-by: Gabriel Azevedo Ferreira <[email protected]>
Co-authored-by: Richard Oentaryo <[email protected]>
  • Loading branch information
6 people authored Apr 18, 2023
1 parent 469d9f3 commit 1da38ae
Show file tree
Hide file tree
Showing 42 changed files with 13,100 additions and 1,620 deletions.
9 changes: 1 addition & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,14 +52,7 @@ CausalNex is a Python package. To install it, simply run:
pip install causalnex
```

Since pygraphviz can be difficult to install, esp. on Windows machines, the requirement is optional.
If you want to use the causalnex native plotting tools, you can use
```bash
pip install "causalnex[plot]"
```
Alternatively, you can use the `networkx` drawing functionality for visualisations with fewer dependencies.

Use `all` for a full installation of dependencies (only the plotting right now):
Use `all` for a full installation of dependencies:
```bash
pip install "causalnex[all]"
```
Expand Down
13 changes: 2 additions & 11 deletions causalnex/plots/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,22 +29,13 @@
"""
``causalnex.plots`` provides functionality to visualise structure models.
"""

__all__ = [
"plot_structure",
"NODE_STYLE",
"EDGE_STYLE",
"GRAPH_STYLE",
"color_gradient_string",
"display_plot_ipython",
"display_plot_mpl",
]

from .display import display_plot_ipython, display_plot_mpl
from .plots import (
EDGE_STYLE,
GRAPH_STYLE,
NODE_STYLE,
color_gradient_string,
plot_structure,
)
from .display import display_plot_ipython
from .plots import EDGE_STYLE, GRAPH_STYLE, NODE_STYLE, plot_structure
121 changes: 39 additions & 82 deletions causalnex/plots/display.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,97 +25,54 @@
#
# See the License for the specific language governing permissions and
# limitations under the License.
"""Methods to display styled pygraphgiz plots."""
"""Methods to display styled pyvis plots."""
import json
from html import escape
from typing import Dict

import io
from typing import Any, Tuple
from IPython.lib.display import IFrame
from pyvis.network import Network

try:
from pygraphviz.agraph import AGraph
except ImportError:
AGraph = Any

try:
from IPython.display import Image
except ImportError:
Image = Any

try:
import matplotlib.pyplot as plt
from matplotlib.axes import Axes
from matplotlib.figure import Figure
except ImportError:
Axes = Any
Figure = Any


def display_plot_ipython(viz: AGraph, prog: str = "neato") -> Image:
def display_plot_ipython(
viz: Network,
output_filename: str,
layout_kwargs: Dict[str, Dict] = None,
) -> IFrame:
"""
Displays a pygraphviz object using ipython.
Displays a PyVis object using ipython.
Args:
viz: pygraphviz object to render.
prog: The graph layout. Avaliable are:
dot, neato, fdp, sfdp, twopi and circo
viz: pyvis object to render.
output_filename: write html to a given path, e.g. "./plot.html". File as to end in ".html"
layout_kwargs: Dictionary to set the `layout` and `physics` of the graph.
Example:
::
>>> layout_kwargs = {
"physics": {
"solver": "repulsion"
},
"layout": {
"hierarchical": {
"enabled": True
}
}
}
Returns:
IPython Image object. Renders in a notebook.
IPython IFrame object. Renders in a notebook.
Raises:
ImportError: if IPython is not installed (optional dependency).
"""
layout_kwargs = layout_kwargs or {}
viz.set_options(options=json.dumps(layout_kwargs))

if Image is Any:
raise ImportError("display_plot_ipython method requires IPython installed.")

return Image(viz.draw(format="png", prog=prog))


def display_plot_mpl(
viz: AGraph,
prog: str = "neato",
ax: Axes = None,
pixel_size_in: float = 0.01,
) -> Tuple[Figure, Axes]:
"""
Displays a pygraphviz object using matplotlib.
Args:
viz: pygraphviz object to render.
prog: The graph layout. Avaliable are:
dot, neato, fdp, sfdp, twopi and circo
ax: Optional matplotlib axes to plot on.
pixel_size_in: Scaling multiple for the plot.
Returns:
IPython Image object. Renders in a notebook.
Raises:
ImportError: if matplotlib is not installed (optional dependency).
"""

if Figure is Any:
raise ImportError("display_plot_mpl method requires matplotlib installed.")

# bytes:
s = viz.draw(format="png", prog=prog)
# convert to numpy array
array = plt.imread(io.BytesIO(s))
x_dim, y_dim, _ = array.shape
html = viz.generate_html()

# handle passed axis
if ax is not None:
ax.imshow(array)
ax.axis("off")
return None, ax
with open(output_filename, mode="w", encoding="UTF-8") as f:
f.write(html)

# handle new axis
f, ax = plt.subplots(1, 1, figsize=(y_dim * pixel_size_in, x_dim * pixel_size_in))
ax.imshow(array)
ax.axis("off")
f.tight_layout(pad=0.0)
return f, ax
return IFrame(
src=output_filename,
width=viz.width,
height=viz.height,
extras=[f"srcdoc='{escape(viz.generate_html(notebook=False))}'"],
)
Loading

0 comments on commit 1da38ae

Please sign in to comment.