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

Is it possible to save the resulting diagram in DOT format? #441

Open
cldeluna opened this issue Jan 24, 2021 · 8 comments
Open

Is it possible to save the resulting diagram in DOT format? #441

cldeluna opened this issue Jan 24, 2021 · 8 comments

Comments

@cldeluna
Copy link

is it possible to save the resulting diagram in dot notation?

Basically the pyGraphviz equivalent of this:
G.write("file.dot")

It would be nice to be able to keep the dot files under revision control and even "snapshot" drawings in text.

@gabriel-tessier
Copy link
Collaborator

@cldeluna

Thank you for the issue.

@mingrammer

What about using outformat, something like:
with Diagram("Simple Diagram", outformat="dot"):

According to the documentation outformat support this values with png as default, we can add dot.

(png, jpg, svg, and pdf) are allowed.

according to Go-Diagrams readme it generate both.

Go-Diagrams will create a folder in the current working directory with the graphviz DOT file and any image assets.

Which one is better, generate a folder with dot file and the image(s) or only one file depend on the outformat option?

Depends on the choice and If it's ok I can work on it.

I prefer the outformat option because it will remain consistent with the current behavior.

@cldeluna
Copy link
Author

cldeluna commented Jan 25, 2021

Just to add another data point, I do also prefer the outformat option. But a question, would it be possible to have multiple outformats? Otherwise, Id have to do a run to generate the image (JPG, PNG,etc.) and then another one to generate the dot file...that may be why the Go-Diagrams approach does both. Alternatively I would execute and generate the dot file but then I'd have to be able to read in the dot file with diagrams and render it. Is that possible?

@clayms
Copy link

clayms commented Jan 25, 2021

A Graphviz dot file is created each time you generate an output. This library then deletes the dot file leaving only the image.

I have tried to change the code that removes the dot file, but could not find the dot file after I ran my script.

See #436 (comment)

@gabriel-tessier
Copy link
Collaborator

@cldeluna
I pushed a change to allow to generate .dot file and be able to output several format in one call. I hope my change cover your needs.

using grouped workers example from the website with outformat=["png", "dot"]

from diagrams import Diagram
from diagrams.aws.compute import EC2
from diagrams.aws.database import RDS
from diagrams.aws.network import ELB

with Diagram("Grouped Workers", show=False, direction="TB", outformat=["png", "dot"]):
    ELB("lb") >> [EC2("worker1"),
                  EC2("worker2"),
                  EC2("worker3"),
                  EC2("worker4"),
                  EC2("worker5")] >> RDS("events")

Generating this png file:

grouped_workers

and a dot file with this content:

digraph "Grouped Workers" {
	graph [bb="0,0,677,544",
		fontcolor="#2D3436",
		fontname="Sans-Serif",
		fontsize=15,
		label="Grouped Workers",
		lheight=0.24,
		lp="338.5,12.5",
		lwidth=1.72,
		nodesep=0.60,
		pad=2.0,
		rankdir=TB,
		ranksep=0.75,
		splines=ortho
	];
	node [fixedsize=true,
		fontcolor="#2D3436",
		fontname="Sans-Serif",
		fontsize=13,
		height=1.4,
		imagescale=true,
		label="\N",
		labelloc=b,
		shape=box,
		style=rounded,
		width=1.4
	];
	edge [color="#7B8894"];
	"2d62583dfd8245d2accd11bc42aa604d"	[height=1.9028,
		image="/usr/src/diagrams/resources/aws/network/elastic-load-balancing.png",
		label=lb,
		pos="338.5,475.5",
		shape=none,
		width=1.4028];
	b51be24db13042aab70e2e0e777e6545	[height=1.9028,
		image="/usr/src/diagrams/resources/aws/compute/ec2.png",
		label=worker1,
		pos="50.5,284.5",
		shape=none,
		width=1.4028];
	"2d62583dfd8245d2accd11bc42aa604d" -> b51be24db13042aab70e2e0e777e6545	[dir=forward,
		fontcolor="#2D3436",
		fontname="Sans-Serif",
		fontsize=13,
		pos="e,50.5,353.23 287.67,498 205,498 50.5,498 50.5,498 50.5,498 50.5,363.23 50.5,363.23"];
	aabdd269c3f64c918195432aa9aedb51	[height=1.9028,
		image="/usr/src/diagrams/resources/aws/compute/ec2.png",
		label=worker2,
		pos="194.5,284.5",
		shape=none,
		width=1.4028];
	"2d62583dfd8245d2accd11bc42aa604d" -> aabdd269c3f64c918195432aa9aedb51	[dir=forward,
		fontcolor="#2D3436",
		fontname="Sans-Serif",
		fontsize=13,
		pos="e,194.5,353.11 287.73,452 246.27,452 194.5,452 194.5,452 194.5,452 194.5,363.11 194.5,363.11"];
	"21f9de773bdd4e4f98ce4e5a3df4a631"	[height=1.9028,
		image="/usr/src/diagrams/resources/aws/compute/ec2.png",
		label=worker3,
		pos="338.5,284.5",
		shape=none,
		width=1.4028];
	"2d62583dfd8245d2accd11bc42aa604d" -> "21f9de773bdd4e4f98ce4e5a3df4a631"	[dir=forward,
		fontcolor="#2D3436",
		fontname="Sans-Serif",
		fontsize=13,
		pos="e,338.5,353.22 338.5,406.81 338.5,406.81 338.5,363.22 338.5,363.22"];
	a8c9872205ed421083510d5d74996188	[height=1.9028,
		image="/usr/src/diagrams/resources/aws/compute/ec2.png",
		label=worker4,
		pos="482.5,284.5",
		shape=none,
		width=1.4028];
	"2d62583dfd8245d2accd11bc42aa604d" -> a8c9872205ed421083510d5d74996188	[dir=forward,
		fontcolor="#2D3436",
		fontname="Sans-Serif",
		fontsize=13,
		pos="e,482.5,353.11 389.27,452 430.73,452 482.5,452 482.5,452 482.5,452 482.5,363.11 482.5,363.11"];
	"4286f7e4faa0404e887f86aef69cd96e"	[height=1.9028,
		image="/usr/src/diagrams/resources/aws/compute/ec2.png",
		label=worker5,
		pos="626.5,284.5",
		shape=none,
		width=1.4028];
	"2d62583dfd8245d2accd11bc42aa604d" -> "4286f7e4faa0404e887f86aef69cd96e"	[dir=forward,
		fontcolor="#2D3436",
		fontname="Sans-Serif",
		fontsize=13,
		pos="e,626.5,353.23 389.33,498 472,498 626.5,498 626.5,498 626.5,498 626.5,363.23 626.5,363.23"];
	"1d6cb893592146d59ca99c297a816619"	[height=1.9028,
		image="/usr/src/diagrams/resources/aws/database/rds.png",
		label=events,
		pos="338.5,93.5",
		shape=none,
		width=1.4028];
	b51be24db13042aab70e2e0e777e6545 -> "1d6cb893592146d59ca99c297a816619"	[dir=forward,
		fontcolor="#2D3436",
		fontname="Sans-Serif",
		fontsize=13,
		pos="e,287.67,70 50.5,215.75 50.5,153.01 50.5,70 50.5,70 50.5,70 277.67,70 277.67,70"];
	aabdd269c3f64c918195432aa9aedb51 -> "1d6cb893592146d59ca99c297a816619"	[dir=forward,
		fontcolor="#2D3436",
		fontname="Sans-Serif",
		fontsize=13,
		pos="e,287.73,116 194.5,215.96 194.5,169.31 194.5,116 194.5,116 194.5,116 277.73,116 277.73,116"];
	"21f9de773bdd4e4f98ce4e5a3df4a631" -> "1d6cb893592146d59ca99c297a816619"	[dir=forward,
		fontcolor="#2D3436",
		fontname="Sans-Serif",
		fontsize=13,
		pos="e,338.5,162.22 338.5,215.81 338.5,215.81 338.5,172.22 338.5,172.22"];
	a8c9872205ed421083510d5d74996188 -> "1d6cb893592146d59ca99c297a816619"	[dir=forward,
		fontcolor="#2D3436",
		fontname="Sans-Serif",
		fontsize=13,
		pos="e,389.27,116 482.5,215.96 482.5,169.31 482.5,116 482.5,116 482.5,116 399.27,116 399.27,116"];
	"4286f7e4faa0404e887f86aef69cd96e" -> "1d6cb893592146d59ca99c297a816619"	[dir=forward,
		fontcolor="#2D3436",
		fontname="Sans-Serif",
		fontsize=13,
		pos="e,389.33,70 626.5,215.75 626.5,153.01 626.5,70 626.5,70 626.5,70 399.33,70 399.33,70"];
}

@clayms
Copy link

clayms commented Mar 15, 2021

A Graphviz dot file is created each time you generate an output. This library then deletes the dot file leaving only the image.

I have tried to change the code that removes the dot file, but could not find the dot file after I ran my script.

See #436 (comment)

Actually, you don't need to change any of the code at all, just call the .dot method on the diagram object, and then the .save method on that.

Using @gabriel-tessier 's example:

from diagrams import Diagram
from diagrams.aws.compute import EC2
from diagrams.aws.database import RDS
from diagrams.aws.network import ELB

with Diagram("Grouped Workers", show=False, direction="TB", ) as diag:
    ELB("lb") >> [EC2("worker1"),
                  EC2("worker2"),
                  EC2("worker3"),
                  EC2("worker4"),
                  EC2("worker5")] >> RDS("events")

diag.dot.save(filename="aws.gv")

Contents of "aws.gv"

digraph "Grouped Workers" {
	graph [fontcolor="#2D3436" fontname="Sans-Serif" fontsize=15 label="Grouped Workers" nodesep=0.60 pad=2.0 rankdir=TB ranksep=0.75 splines=ortho]
	node [fixedsize=true fontcolor="#2D3436" fontname="Sans-Serif" fontsize=13 height=1.4 imagescale=true labelloc=b shape=box style=rounded width=1.4]
	edge [color="#7B8894"]
	"9f3f6dfd35bd41779b74a6245dc0eac7" [label=lb height=1.9 image="/home/user/miniconda/envs/diagrams/lib/python3.6/site-packages/resources/aws/network/elastic-load-balancing.png" shape=none]
	"916e9529f6304413b778746af465701f" [label=worker1 height=1.9 image="/home/user/miniconda/envs/diagrams/lib/python3.6/site-packages/resources/aws/compute/ec2.png" shape=none]
	"2cdf874d396d424faa23c1bcd93174a2" [label=worker2 height=1.9 image="/home/user/miniconda/envs/diagrams/lib/python3.6/site-packages/resources/aws/compute/ec2.png" shape=none]
	"092e81b626c14826b9c9328128f096bf" [label=worker3 height=1.9 image="/home/user/miniconda/envs/diagrams/lib/python3.6/site-packages/resources/aws/compute/ec2.png" shape=none]
	a0dc07c8105b4410a5ef7cd522025fe2 [label=worker4 height=1.9 image="/home/user/miniconda/envs/diagrams/lib/python3.6/site-packages/resources/aws/compute/ec2.png" shape=none]
	e23a149f10384035914e6f7cd6bb843d [label=worker5 height=1.9 image="/home/user/miniconda/envs/diagrams/lib/python3.6/site-packages/resources/aws/compute/ec2.png" shape=none]
	"9f3f6dfd35bd41779b74a6245dc0eac7" -> "916e9529f6304413b778746af465701f" [dir=forward fontcolor="#2D3436" fontname="Sans-Serif" fontsize=13]
	"9f3f6dfd35bd41779b74a6245dc0eac7" -> "2cdf874d396d424faa23c1bcd93174a2" [dir=forward fontcolor="#2D3436" fontname="Sans-Serif" fontsize=13]
	"9f3f6dfd35bd41779b74a6245dc0eac7" -> "092e81b626c14826b9c9328128f096bf" [dir=forward fontcolor="#2D3436" fontname="Sans-Serif" fontsize=13]
	"9f3f6dfd35bd41779b74a6245dc0eac7" -> a0dc07c8105b4410a5ef7cd522025fe2 [dir=forward fontcolor="#2D3436" fontname="Sans-Serif" fontsize=13]
	"9f3f6dfd35bd41779b74a6245dc0eac7" -> e23a149f10384035914e6f7cd6bb843d [dir=forward fontcolor="#2D3436" fontname="Sans-Serif" fontsize=13]
	"74a2b8bde2c84310b0d551f214b45d26" [label=events height=1.9 image="/home/user/miniconda/envs/diagrams/lib/python3.6/site-packages/resources/aws/database/rds.png" shape=none]
	"916e9529f6304413b778746af465701f" -> "74a2b8bde2c84310b0d551f214b45d26" [dir=forward fontcolor="#2D3436" fontname="Sans-Serif" fontsize=13]
	"2cdf874d396d424faa23c1bcd93174a2" -> "74a2b8bde2c84310b0d551f214b45d26" [dir=forward fontcolor="#2D3436" fontname="Sans-Serif" fontsize=13]
	"092e81b626c14826b9c9328128f096bf" -> "74a2b8bde2c84310b0d551f214b45d26" [dir=forward fontcolor="#2D3436" fontname="Sans-Serif" fontsize=13]
	a0dc07c8105b4410a5ef7cd522025fe2 -> "74a2b8bde2c84310b0d551f214b45d26" [dir=forward fontcolor="#2D3436" fontname="Sans-Serif" fontsize=13]
	e23a149f10384035914e6f7cd6bb843d -> "74a2b8bde2c84310b0d551f214b45d26" [dir=forward fontcolor="#2D3436" fontname="Sans-Serif" fontsize=13]
}

@cldeluna
Copy link
Author

cldeluna commented May 15, 2021

@gabriel-tessier - thank you for the update to allow saving the dot file.
when I change my code to use that new feature
with Diagram( f"\n{site_name}\nCurrent Topology", filename=drawing_fp, outformat=["jpg", "dot"], show=False, direction=direction, graph_attr=graph_attr, ):

it looks like an additional update is needed to deal with the list:

Traceback (most recent call last):
File "root_diagram.py", line 1671, in
main()
File "root_diagram.py", line 1613, in main
main_processing(vars(arguments))
File "root_diagram.py", line 1223, in main_processing
with Diagram(
File "/Users/claudia/vEnvs/net_refresh/lib/python3.8/site-packages/diagrams/init.py", line 130, in init
if not self._validate_outformat(outformat):
File "/Users/claudia/vEnvs/net_refresh/lib/python3.8/site-packages/diagrams/init.py", line 172, in _validate_outformat
outformat = outformat.lower()
AttributeError: 'list' object has no attribute 'lower'
(net_refresh) claudia@Claudias-iMac network_refresh %

I then tried @clayms suggestion which actually does generate the dot file but does error out:
In this case the outformat goes back to a single string and I add the "as diag":
with Diagram( f"\n{site_name}\nCurrent Topology", filename=drawing_fp, outformat="jpg", show=False, direction=direction, graph_attr=graph_attr, ) as diag:

I then add:
`        diag.dot.save(filename="test.dot")`

Error:

Traceback (most recent call last):
File "root_diagram.py", line 1671, in
main()
File "root_diagram.py", line 1613, in main
main_processing(vars(arguments))
File "root_diagram.py", line 1567, in main_processing
diag.dot.save(filename="test.dot")
File "/Users/claudia/vEnvs/net_refresh/lib/python3.8/site-packages/diagrams/init.py", line 151, in exit
os.remove(self.filename)
FileNotFoundError: [Errno 2] No such file or directory: '/some_dir/Current_Topology'

The dot file is generated but in trying to remove the file path I set in drawing_fp it errors out as there is no such file.

Before the updates, where drawing_fp = 'Current_Topology" and where outformat="jpg", i get a file "Current_Topology.jpg" in the desired directory. It looks like the code is trying to remove the file "Current_Topology.jpg" (which I need to keep) but since my variable drawing_fp == 'Current_Topology' it is not found.

A bit more testing.

if I pass diag.dot.save(filename=drawing_fp) ...essentially the filepath attribute from the Drawing class, it does not error out but I don't get the .dot file either.

with this I get two files
diag.dot.save(filename=f"{drawing_fp}.dot")

I get a Current_Topology.dot.jpg drawing and a Current_Topology.dot file which looks to be a valid dot file but it errors out on the os.remove(self.filename)

Let me know what other information I can provide!

@gabriel-tessier
Copy link
Collaborator

@cldeluna
if you use the latest version the error is "correct" as the PR is not yet merged.
You can follow the last changes here:
#446

@cldeluna
Copy link
Author

Thank you @gabriel-tessier, I had not realized that. FWIW I like the option of passing outformat a list. Apart from saving the dot file it could have broader uses...if I wanted to generate a PNG and JPG for the same diagram or JPG and SVG. It all works the same and the specifics of generating the requested format are done "behind the scenes". I'll keep an eye out on #446 and use @clayms workaround in the meantime.

mingrammer pushed a commit that referenced this issue Feb 9, 2022
…#592)

* feat(output): Generate dot file and support multi outformat.(#441)

* [fix] forget to clean the dot generated file.

* [fix] indentation

* [fix] Review + add more cases in unittest

* [fix] Add dot in the test
haad added a commit to haad/diagrams that referenced this issue May 12, 2022
* mhmdio/master:
  bump: up to version 0.21.1
  feat(output): Generate dot file and support multi outformat.(mingrammer#441) Re (mingrammer#592)
  feat: add digitalocean provider (mingrammer#646)
  docs(website): update docs
  bump: up to version 0.21.0
  docs(readme): update badges
  docs(readme): update
  docs(readme): add digital ocean badge
  feat(provider): added DigitalOcean provider (mingrammer#621)
  feat(node): Dremio Service in OnPrem.Analytics (mingrammer#451)
  chore(deps): bump shelljs from 0.8.4 to 0.8.5 in /website (mingrammer#641)
  feat(node): add Nagios in OnPrem monitoring (mingrammer#638)
  feat(node): adding GCP API gateway image (mingrammer#636)
  feat(node): add chatbot icon (mingrammer#633)
  chore(deps): bump graphviz from 0.17 to 0.19.1 (mingrammer#635)
  feat(node): added Dapr programming runtime (mingrammer#591)
  docs: add mac dev guide (mingrammer#576)
  docs(readme): add Python 3.9 to badges (mingrammer#584)
  👌 IMPROVE: HashiCorp Icons
  📦 NEW: Add remaining HashiCorp Icons
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants