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

Import tables #389

Open
stanbiryukov opened this issue Dec 2, 2020 · 8 comments
Open

Import tables #389

stanbiryukov opened this issue Dec 2, 2020 · 8 comments

Comments

@stanbiryukov
Copy link

Thoughts on enabling a class to import a small pandas dataframe/table to use in annotation?

Here's a good example of what I'm referencing where network diagrams typically have tables including information like source, destination, direction etc: https://knowledgebase.paloaltonetworks.com/KCSArticleDetail?id=kA10g000000ClD6CAK

Workaround right now is to dump the table as a png and weave it in as a Custom "icon"

@clayms
Copy link

clayms commented Dec 2, 2020

Have you seen this

#290 (comment)

@stanbiryukov
Copy link
Author

I didn't see that. It's helpful but still looks extremely manual, especially when trying to format a table with networking configuration.

@stanbiryukov
Copy link
Author

Is there a way to re-format and inject an html table into Node as a label? Here's what I'm thinking so far:

import pandas as pd
html = pd.DataFrame({'Directon': ['ingress', 'egress'], 'Source': ['10.XXX.X.XXX', '10.XXX.X.XXX']}).to_html()
nd = Node(label=html) # fails

@wolfspyre
Copy link
Contributor

wolfspyre commented Dec 2, 2020 via email

@clayms
Copy link

clayms commented Dec 2, 2020

You just have to remove the html tags that pandas adds that Graphviz does not understand. Additionally, you have to wrap your HTML text label in angle brackets to let Graphviz know this is an HTML node. See example code below.

Also see https://graphviz.gitlab.io/doc/info/shapes.html#html (emphasis mine):

NOTE: The features and syntax supported by these labels are modeled on HTML. However, there are many aspects that are relevant to Graphviz labels that are not in HTML and, conversely, HTML allows various constructs which are meaningless in Graphviz. We will generally refer to these labels as "HTML labels" rather than the cumbersome "HTML-like labels" but the reader is warned that these are not really HTML. The grammar below describes precisely what Graphviz will accept.

You can use the re library to clean this up some more, but you get the general idea.
Also, depending on the size of your HTML table, you'll have to play with the width and height to get the Edge head and tail to intersect your HTML table node correctly.

import pandas as pd
from diagrams import Diagram, Edge, Node

html = (pd.DataFrame({
        'Directon': ['ingress', 'egress'], 
        'Source': ['10.XXX.X.XXX', '10.XXX.X.XXX']})
    .to_html()
    .replace(' class="dataframe"','')
    .replace("<thead>","")
    .replace("</thead>","")
    .replace("<tbody>","")
    .replace("</tbody>","")
    .replace("<th>","<td>")
    .replace("</th>","</td>")
)


with Diagram("HTML table Node", show=False) as diag:
    N1 = Node(shape="cds", label="N1", labelloc="c",)
    nd = Node(shape="plaintext", label="<"+html+">", width="2.8", height="1")
    N2 = Node(shape="triangle", label="N2", labelloc="c",)

    N1 >> Edge() >> nd >> Edge() >> N2

diag

image

@clayms
Copy link

clayms commented Dec 2, 2020

Here is the Graphviz example recreated using this library:

from diagrams import Diagram, Edge, Node

html_node_1 = """<
    <TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0">
    <TR><TD>left</TD><TD PORT="f1">middle</TD><TD PORT="f2">right</TD></TR>
    </TABLE>
    >"""

html_node_2 = """<
    <TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0">
    <TR><TD PORT="f0">one</TD><TD>two</TD></TR>
    </TABLE>
    >"""

html_node_3 = """<
    <TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0" CELLPADDING="4">
    <TR>
        <TD ROWSPAN="3">hello<BR/>world</TD>
        <TD COLSPAN="3">b</TD>
        <TD ROWSPAN="3">g</TD>
        <TD ROWSPAN="3">h</TD>
    </TR>
    <TR>
        <TD>c</TD><TD PORT="here">d</TD><TD>e</TD>
    </TR>
    <TR>
        <TD COLSPAN="3">f</TD>
    </TR>
    </TABLE>
    >"""


graph_attr = {
    "splines":"spline",
}

with Diagram("\n\nGraphviz Example of HTML lables", show=False, direction="TB", graph_attr=graph_attr) as diag:
    struct1 = Node(shape="plaintext", label=html_node_1, width="1.0", height="0.0",)
    struct2 = Node(shape="plaintext", label=html_node_2, width="1.0", height="0.5",)
    struct3 = Node(shape="plaintext", label=html_node_3, width="3.0", height="0.8",)

    struct1 >> Edge(tailport="f1", headport="f0") >> struct2
    struct1 >> Edge(tailport="f2", headport="here") >> struct3


diag

image

@clayms
Copy link

clayms commented Dec 2, 2020

And why not...
Below is the more complex Graphviz example recreated with this library.

from diagrams import Diagram, Node, Edge

html_node_a = """<
    <TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0">
    <TR><TD ROWSPAN="3" BGCOLOR="yellow">class</TD></TR>
    <TR><TD PORT="here" BGCOLOR="lightblue">qualifier</TD></TR>
    </TABLE>
    >"""

html_node_b = """<
    <TABLE BGCOLOR="bisque">
    <TR><TD COLSPAN="3">elephant</TD> 
        <TD ROWSPAN="2" BGCOLOR="chartreuse" 
            VALIGN="bottom" ALIGN="right">two</TD> </TR>
    <TR><TD COLSPAN="2" ROWSPAN="2">
            <TABLE BGCOLOR="grey">
            <TR> <TD>corn</TD> </TR> 
            <TR> <TD BGCOLOR="yellow">c</TD> </TR> 
            <TR> <TD>f</TD> </TR> 
            </TABLE> </TD>
        <TD BGCOLOR="white">penguin</TD> 
    </TR> 
    <TR> <TD COLSPAN="2" BORDER="4" ALIGN="right" PORT="there">4</TD> </TR>
    </TABLE>
    >"""

html_node_c = """<
    long line 1<BR/>line 2<BR ALIGN="LEFT"/>line 3<BR ALIGN="RIGHT"/>
    >"""

html_edge_d2c = """<
    <TABLE>
    <TR><TD BGCOLOR="red" WIDTH="10"> </TD>
        <TD>Edge labels<BR/>also</TD>
        <TD BGCOLOR="blue" WIDTH="10"> </TD>
    </TR>
    </TABLE>
    >"""

graph_attr = {
    "splines":"spline",
}

with Diagram("\n\nGraphviz Example of HTML lables", show=False, graph_attr=graph_attr) as diag:
    a = Node(shape="plaintext", label=html_node_a, width="1.5", height="0.2",)
    b = Node(shape="ellipse", style="filled", label=html_node_b, labelloc="c",width="3.5", height="2.5",)
    c = Node(shape="plaintext", label=html_node_c, width="2.0", height="1.0",)
    d = Node(shape="triangle", style="solid", label="d", labelloc="c", width="1.0", height="0.8",)

    a << Edge(tailport="here", headport="there", arrowtail="diamond") >> b
    c >> Edge(minlen="0") >> b
    d >> Edge(label=html_edge_d2c) >> c


diag

image

@stanbiryukov
Copy link
Author

Thanks, @clayms. These are great examples to point to and makes creating table schema with diagrams a tractable option. Thoughts on adding a HTML parsing class to diagrams that can translate pandas html to the graphvis html label grammar?

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