31

I am trying to display a simple graph using pydot.

My question is that is there any way to display the graph without writing it to a file as currently I use write function to first draw and then have to use the Image module to show the files.

However is there any way that the graph directly gets printed on the screen without being saved ??


Also as an update I would like to ask in this same question that I observe that while the image gets saved very quickly when I use the show command of the Image module it takes noticeable time for the image to be seen .... Also sometimes I get the error that the image could'nt be opened because it was either deleted or saved in unavailable location which is not correct as I am saving it at my Desktop..... Does anyone know what's happening and is there a faster way to get the image loaded.....

Thanks a lot....

eumiro
  • 207,213
  • 34
  • 299
  • 261
  • Related: http://stackoverflow.com/questions/10379448/plotting-directed-graphs-in-python-in-a-way-that-show-all-edges-separately/17823100#17823100 – 0 _ Aug 30 '13 at 00:14
  • related but applied to pygraphviz: https://stackoverflow.com/questions/18608316/capture-pygraphviz-image-rendering-without-saving-to-a-file/18610140#comment119200221_18610140 I'd love to know how to do it in pygraphviz too. – Charlie Parker May 07 '21 at 16:45

7 Answers7

34

Here's a simple solution using IPython:

from IPython.display import Image, display

def view_pydot(pdot):
    plt = Image(pdot.create_png())
    display(plt)

Example usage:

import networkx as nx
to_pdot = nx.drawing.nx_pydot.to_pydot
pdot = to_pdot(nx.complete_graph(5))
view_pydot(pdot)
micahscopes
  • 1,034
  • 1
  • 9
  • 12
  • 4
    This should be the accepted answer. Exactly what I needed: To just immediately display the graph with as few lines as possible with the console (e.g. spyder) – kushy Aug 09 '18 at 14:21
29

You can render the image from pydot by calling GraphViz's dot without writing any files to the disk. Then just plot it. This can be done as follows:

import io

import matplotlib.pyplot as plt
import matplotlib.image as mpimg
import networkx as nx

# create a `networkx` graph
g = nx.MultiDiGraph()
g.add_nodes_from([1,2])
g.add_edge(1, 2)

# convert from `networkx` to a `pydot` graph
pydot_graph = nx.drawing.nx_pydot.to_pydot(g)

# render the `pydot` by calling `dot`, no file saved to disk
png_str = pydot_graph.create_png(prog='dot')

# treat the DOT output as an image file
sio = io.BytesIO()
sio.write(png_str)
sio.seek(0)
img = mpimg.imread(sio)

# plot the image
imgplot = plt.imshow(img, aspect='equal')
plt.show()

This is particularly useful for directed graphs.

See also this pull request, which introduces such capabilities directly to networkx.

0 _
  • 10,524
  • 11
  • 77
  • 109
  • 5
    Just as a quick addendum, if you're in a notebook you can render `png_str` (bytes) directly using `Image(png_str)` (from `IPython.display`). – meloncholy Jan 02 '15 at 16:52
  • Made some minor adjustments in this adaptation: https://github.com/EricCousineau-TRI/repro/blob/d74ecbd4fdfdaa115bf28b2db15c7e296553435d/python/matplotlib/graphviz.py#L9 Thanks for posting this code! (Ended up just using `pydot`, as that was able to handle the graph of interest in this case.) – Eric Cousineau Dec 12 '17 at 23:10
  • 2
    @EricCousineau By the statement `g = pydot.graph_from_dot_data(dot_text)` it appears that you are using an older `pydot` version. Please note that as of `pydot == 1.2.3`, the function `graph_from_dot_data` returns a `list` in all cases (in previous versions it returned a graph when singleton). See also [this comment](https://github.com/erocarrera/pydot/issues/159#issuecomment-334799706), and https://github.com/erocarrera/pydot/blob/35a8d858bd9da0b37268fe9b317fe4895387e75f/pydot.py#L235, https://github.com/erocarrera/pydot/blob/35a8d858bd9da0b37268fe9b317fe4895387e75f/dot_parser.py#L545. – 0 _ Dec 12 '17 at 23:46
  • 1
    Ah, thank you! (Updated: https://github.com/EricCousineau-TRI/repro/blob/51e8020/python/matplotlib/graphviz.py#L9 ) – Eric Cousineau Dec 13 '17 at 20:37
  • Is there a way to also preserve edge labels within the image? – Chris Feb 20 '22 at 19:58
4

Based on this answer (how to show images in python), here's a few lines:

gr = ... <pydot.Dot instance> ...

import tempfile, Image
fout = tempfile.NamedTemporaryFile(suffix=".png")
gr.write(fout.name,format="png")
Image.open(fout.name).show()

Image is from the Python Imaging Library

Community
  • 1
  • 1
Andre Holzner
  • 18,333
  • 6
  • 54
  • 63
  • As of March 2019, Python Imaging Library is mostly replaced by [Pillow](https://pillow.readthedocs.io/en/stable/) – Ignatius Apr 08 '19 at 01:47
2

IPython.display.SVG method embeds an SVG into the display and can be used to display graph without saving to a file.

Here, keras.utils.model_to_dot is used to convert a Keras model to dot format.

from IPython.display import SVG
from tensorflow import keras

#Create a keras model.
model = keras.models.Sequential()
model.add(keras.layers.Dense(units=2, input_shape=(2,1), activation='relu'))
model.add(keras.layers.Dense(units=1, activation='relu'))

#model visualization
SVG(keras.utils.model_to_dot(model).create(prog='dot', format='svg'))
1

This worked for me inside a Python 3 shell (requires the Pillow package):

import pydot
from PIL import Image
from io import BytesIO

graph = pydot.Dot(graph_type="digraph")
node = pydot.Node("Hello pydot!")
graph.add_node(node)

Image.open(BytesIO(graph.create_png())).show()

You can also add a method called _repr_html_ to an object with a pydot graph member to render a nice crisp SVG inside a Jupyter notebook:

class MyClass:
    def __init__(self, graph):
        self.graph = graph

    def _repr_html_(self):
        return self.graph.create_svg().decode("utf-8")
breandan
  • 1,965
  • 26
  • 45
0

I'm afraid pydot uses graphviz to render the graphs. I.e., it runs the executable and loads the resulting image.

Bottom line - no, you cannot avoid creating the file.

0 _
  • 10,524
  • 11
  • 77
  • 109
nimrodm
  • 23,081
  • 7
  • 58
  • 59
0

It works well with AGraph Class as well

https://pygraphviz.github.io/documentation/latest/reference/agraph.html#pygraphviz.AGraph.draw

If path is None, the result is returned as a Bytes object.

So, just omit this argument to return the image data without saving it to disk

Using

from networkx.drawing.nx_agraph import graphviz_layout, to_agraph
g = nx.Graph()
...
A = to_agraph(g)
A.draw()

https://networkx.org/documentation/stable/reference/drawing.html#module-networkx.drawing.nx_agraph

In order to show the resulting image which is saved as Bytes object:

# create image without saving to disk
img = A.draw(format='png')
image = Image.open(BytesIO(img))
image.show(title="Graph")

it needs

from PIL import Image
from io import BytesIO
pas-calc
  • 115
  • 9
  • for me this doesn't put out a window with a picture of the graph... – Charlie Parker May 07 '21 at 16:44
  • Now I expanded my answer and included a code snippet to show the graph. The `img` is the resulting "Bytes object" that can be displayed or otherwise processed. In this example I demonstrate how to display it without saving to disk – pas-calc May 08 '21 at 19:17