Draws graph using GraphViz.

        The networkx graph object itself can also be drawn
        with networkx's in-built graph drawing methods, but
        note that this might give misleading results for
        multigraphs (edges are super-imposed on each other).

        If visualization is difficult to interpret,
        `hide_image_edges` can help, especially in larger
        graphs.

        :param filename: filename to output, will detect filetype
        from extension (any graphviz filetype supported, such as
        pdf or png)
        :param diff (StructureGraph): an additional graph to
        compare with, will color edges red that do not exist in diff
        and edges green that are in diff graph but not in the
        reference graph
        :param hide_unconnected_nodes: if True, hide unconnected
        nodes
        :param hide_image_edges: if True, do not draw edges that
        go through periodic boundaries
        :param edge_colors (bool): if True, use node colors to
        color edges
        :param node_labels (bool): if True, label nodes with
        species and site index
        :param weight_labels (bool): if True, label edges with
        weights
        :param image_labels (bool): if True, label edges with
        their periodic images (usually only used for debugging,
        edges to periodic images always appear as dashed lines)
        :param color_scheme (str): "VESTA" or "JMOL"
        :param keep_dot (bool): keep GraphViz .dot file for later
        visualization
        :param algo: any graphviz algo, "neato" (for simple graphs)
        or "fdp" (for more crowded graphs) usually give good outputs
        :return:

def draw_graph_to_file(self, filename="graph",
                           diff=None,
                           hide_unconnected_nodes=False,
                           hide_image_edges=True,
                           edge_colors=False,
                           node_labels=False,
                           weight_labels=False,
                           image_labels=False,
                           color_scheme="VESTA",
                           keep_dot=False,
                           algo="fdp"):
        """
        Draws graph using GraphViz.

        The networkx graph object itself can also be drawn
        with networkx's in-built graph drawing methods, but
        note that this might give misleading results for
        multigraphs (edges are super-imposed on each other).

        If visualization is difficult to interpret,
        `hide_image_edges` can help, especially in larger
        graphs.

        :param filename: filename to output, will detect filetype
        from extension (any graphviz filetype supported, such as
        pdf or png)
        :param diff (StructureGraph): an additional graph to
        compare with, will color edges red that do not exist in diff
        and edges green that are in diff graph but not in the
        reference graph
        :param hide_unconnected_nodes: if True, hide unconnected
        nodes
        :param hide_image_edges: if True, do not draw edges that
        go through periodic boundaries
        :param edge_colors (bool): if True, use node colors to
        color edges
        :param node_labels (bool): if True, label nodes with
        species and site index
        :param weight_labels (bool): if True, label edges with
        weights
        :param image_labels (bool): if True, label edges with
        their periodic images (usually only used for debugging,
        edges to periodic images always appear as dashed lines)
        :param color_scheme (str): "VESTA" or "JMOL"
        :param keep_dot (bool): keep GraphViz .dot file for later
        visualization
        :param algo: any graphviz algo, "neato" (for simple graphs)
        or "fdp" (for more crowded graphs) usually give good outputs
        :return:
        """

        if not which(algo):
            raise RuntimeError("StructureGraph graph drawing requires "
                               "GraphViz binaries to be in the path.")

        # Developer note: NetworkX also has methods for drawing
        # graphs using matplotlib, these also work here. However,
        # a dedicated tool like GraphViz allows for much easier
        # control over graph appearance and also correctly displays
        # mutli-graphs (matplotlib can superimpose multiple edges).

        g = self.graph.copy()

        g.graph = {'nodesep': 10.0, 'dpi': 300, 'overlap': "false"}

        # add display options for nodes
        for n in g.nodes():

            # get label by species name
            label = "{}({})".format(str(self.structure[n].specie), n) if node_labels else ""

            # use standard color scheme for nodes
            c = EL_COLORS[color_scheme].get(str(self.structure[n].specie.symbol), [0, 0, 0])

            # get contrasting font color
            # magic numbers account for perceived luminescence
            # https://stackoverflow.com/questions/1855884/determine-font-color-based-on-background-color
            fontcolor = '#000000' if 1 - (c[0] * 0.299 + c[1] * 0.587
                                          + c[2] * 0.114) / 255 < 0.5 else '#ffffff'

            # convert color to hex string
            color = "#{:02x}{:02x}{:02x}".format(c[0], c[1], c[2])

            g.add_node(n, fillcolor=color, fontcolor=fontcolor, label=label,
                       fontname="Helvetica-bold", style="filled", shape="circle")

        edges_to_delete = []

        # add display options for edges
        for u, v, k, d in g.edges(keys=True, data=True):

            # retrieve from/to images, set as origin if not defined
            to_image = d['to_jimage']

            # set edge style
            d['style'] = "solid"
            if to_image != (0, 0, 0):
                d['style'] = "dashed"
                if hide_image_edges:
                    edges_to_delete.append((u, v, k))

            # don't show edge directions
            d['arrowhead'] = "none"

            # only add labels for images that are not the origin
            if image_labels:
                d['headlabel'] = "" if to_image == (0, 0, 0) else "to {}".format((to_image))
                d['arrowhead'] = "normal" if d['headlabel'] else "none"

            # optionally color edges using node colors
            color_u = g.node[u]['fillcolor']
            color_v = g.node[v]['fillcolor']
            d['color_uv'] = "{};0.5:{};0.5".format(color_u, color_v) if edge_colors else "#000000"

            # optionally add weights to graph
            if weight_labels:
                units = g.graph.get('edge_weight_units', "")
                if d.get('weight'):
                    d['label'] = "{:.2f} {}".format(d['weight'], units)

            # update edge with our new style attributes
            g.edges[u, v, k].update(d)

        # optionally remove periodic image edges,
        # these can be confusing due to periodic boundaries
        if hide_image_edges:
            for edge_to_delete in edges_to_delete:
                g.remove_edge(*edge_to_delete)

        # optionally hide unconnected nodes,
        # these can appear when removing periodic edges
        if hide_unconnected_nodes:
            g = g.subgraph([n for n in g.degree() if g.degree()[n] != 0])

        # optionally highlight differences with another graph
        if diff:
            diff = self.diff(diff, strict=True)
            green_edges = []
            red_edges = []
            for u, v, k, d in g.edges(keys=True, data=True):
                if (u, v, d['to_jimage']) in diff['self']:
                    # edge has been deleted
                    red_edges.append((u, v, k))
                elif (u, v, d['to_jimage']) in diff['other']:
                    # edge has been added
                    green_edges.append((u, v, k))
            for u, v, k in green_edges:
                g.edges[u, v, k].update({'color_uv': '#00ff00'})
            for u, v, k in red_edges:
                g.edges[u, v, k].update({'color_uv': '#ff0000'})

        basename, extension = os.path.splitext(filename)
        extension = extension[1:]

        write_dot(g, basename+".dot")

        with open(filename, "w") as f:

            args = [algo, "-T", extension, basename+".dot"]
            rs = subprocess.Popen(args,
                                  stdout=f,
                                  stdin=subprocess.PIPE, close_fds=True)
            rs.communicate()
            if rs.returncode != 0:
                raise RuntimeError("{} exited with return code {}.".format(algo, rs.returncode))

        if not keep_dot:
            os.remove(basename+".dot")