From efe6f15f3bfe7f109a34a79da61985d4c9475e84 Mon Sep 17 00:00:00 2001 From: Brennen Raimer <5969754+norweeg@users.noreply.github.com> Date: Wed, 3 Apr 2024 12:08:53 -0400 Subject: [PATCH 1/2] fixes #278 implements #89 --- pyvis/network.py | 52 +++++++++++++++++++++++++++++------------------- pyvis/utils.py | 16 +++++++++------ 2 files changed, 42 insertions(+), 26 deletions(-) diff --git a/pyvis/network.py b/pyvis/network.py index 8deb915..9094226 100644 --- a/pyvis/network.py +++ b/pyvis/network.py @@ -4,6 +4,8 @@ import tempfile import webbrowser from collections import defaultdict +from io import TextIOBase +from pathlib import Path import jsonpickle import networkx as nx @@ -497,41 +499,51 @@ def generate_html(self, name="index.html", local=True, notebook=False): ) return self.html - def write_html(self, name, local=True, notebook=False,open_browser=False): + def write_html(self, html_file, local=True, notebook=False, open_browser=False): """ This method gets the data structures supporting the nodes, edges, and options and updates the template to write the HTML holding the visualization. To work with the old local methods local is being depricated, but not removed. - :type name_html: str - @param name: name of the file to save the graph as. + :type html_file: Union[PathLike, TextIOBase] + @param html_file: path to or file object of the file to save the graph as. @param local: Depricated parameter. Used to be used to determine how the graph needs deploy. Has been removed in favor of using the class cdn_resources instead. @param notebook: If true, this object will return the iframe document for use in juptyer notebook. @param open_browser: If true, will open a web browser with the generated graph. """ - getcwd_name = name - check_html(getcwd_name) + if self.cdn_resources not in ['in_line','remote','local']: + raise ValueError("cdn_resources should be 'local', 'in_line', or 'remote'") + + if isinstance(html_file, TextIOBase): + # the filename of this file object + filename = Path(html_file.name).resolve() + else: + filename = Path(html_file).resolve() + + check_html(filename) self.html = self.generate_html(notebook=notebook) if self.cdn_resources == "local": - if not os.path.exists("lib"): - os.makedirs("lib") - if not os.path.exists("lib/bindings"): - shutil.copytree(f"{os.path.dirname(__file__)}/templates/lib/bindings", "lib/bindings") - if not os.path.exists(os.getcwd()+"/lib/tom-select"): - shutil.copytree(f"{os.path.dirname(__file__)}/templates/lib/tom-select", "lib/tom-select") - if not os.path.exists(os.getcwd()+"/lib/vis-9.1.2"): - shutil.copytree(f"{os.path.dirname(__file__)}/templates/lib/vis-9.1.2", "lib/vis-9.1.2") - with open(getcwd_name, "w+") as out: - out.write(self.html) - elif self.cdn_resources == "in_line" or self.cdn_resources == "remote": - with open(getcwd_name, "w+") as out: - out.write(self.html) + # copy local cdn resources to lib_dir lib_dir will always be a sibling of filename + lib_dir = filename.parent / "lib" + if not lib_dir.exists(): + lib_dir.mkdir(parents=True, exist_ok=True) + if not (lib_dir/"bindings").exists(): + shutil.copytree(Path(__file__)/"templates/lib/bindings", lib_dir/"bindings") + if not (lib_dir/"tom-select").exists(): + shutil.copytree(Path(__file__)/"templates/lib/tom-select", lib_dir/"tom-select") + if not (lib_dir/"vis-9.1.2").exists(): + shutil.copytree(Path(__file__)/"templates/lib/vis-9.1.2", lib_dir/"vis-9.1.2") + + if isinstance(html_file, TextIOBase): + html_file.write(self.html) else: - assert "cdn_resources is not in ['in_line','remote','local']." + with open(filename, "w+") as out: + out.write(self.html) + if open_browser: # open the saved file in a new browser window. - webbrowser.open(getcwd_name) + webbrowser.open(str(filename)) def show(self, name, local=True,notebook=True): diff --git a/pyvis/utils.py b/pyvis/utils.py index 9e394c6..2539985 100644 --- a/pyvis/utils.py +++ b/pyvis/utils.py @@ -1,13 +1,17 @@ # utility and helper functions for use in pyvis +from os import PathLike +from pathlib import Path - -def check_html(name): +def check_html(name: PathLike): """ Given a name of graph to save or write, check if it is of valid syntax :param: name: the name to check - :type name: str + :type name: PathLike """ - assert len(name.split(".")) >= 2, "invalid file type for %s" % name - assert name.split( - ".")[-1] == "html", "%s is not a valid html file" % name + name = Path(name) + if (name.suffix != ".html") or (name.suffixes[-1] != ".html"): + raise ValueError(f"{name} is not a valid html file") + if not name.parent.exists(): + # ensures that the parent folder exists and creates it if it doesn't exist + name.parent.mkdir(parents=True, exist_ok=True) From 01af9d131e06f0c08205380b8349e92af74b04bf Mon Sep 17 00:00:00 2001 From: Brennen Raimer <5969754+norweeg@users.noreply.github.com> Date: Wed, 3 Apr 2024 12:21:29 -0400 Subject: [PATCH 2/2] show can now take any PathLike value for name. removed unnecessary duplicated if notebook clause. Return IFrame in first clause. --- pyvis/network.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pyvis/network.py b/pyvis/network.py index 9094226..0264801 100644 --- a/pyvis/network.py +++ b/pyvis/network.py @@ -551,15 +551,15 @@ def show(self, name, local=True,notebook=True): Writes a static HTML file and saves it locally before opening. :param: name: the name of the html file to save as - :type name: str + :type name: PathLike """ - print(name) + print(str(name)) if notebook: self.write_html(name, open_browser=False,notebook=True) + return IFrame(name, width=self.width, height=self.height) else: self.write_html(name, open_browser=True) - if notebook: - return IFrame(name, width=self.width, height=self.height) + def prep_notebook(self, custom_template=False, custom_template_path=None):