New Node Shape: Typed Node

This is a continuation of How to create a new node type? - #3 by Vithanco. Thanks especially to steveroush for the help provided then.

I still think of node shapes. I would like to have a new node shape as used here:


I will use “Typed Node” or “TNode” for this.

So, a TNode shows a border (edge radius, thickness?) and a class name (font, size, colour) with a background colour - as in the picture. The node text is then shown inside the box.

I believe the right way to create a TNode is to do so within Graphviz itself (most likely as a separate Node Shape), as it should be accessible even in the WASM version, providing SVG output.

Questions:

  • What key concepts need to be understood for this task? I think most of the stuff, such as Node size, shape type and other existing attributes, must be improved. But maybe we need to consider concepts that “break” when this would happen (e.g. I could imagine that there is an impact on ports)
  • What problems would need to be solved for this to succeed? Which classes/packages/methods need to be improved? What new functionality would need to be created? Would we want to refactor things first to create further node class styles?
  • What are some starting points within the code to start this task? Any hints on where changes will be needed would be helpful.
  • How would we need to test this? What would be considered “good” for test cases in this case? Would we need to create an additional test harness for existing functionality as we will touch them?
  • How much work is this? What are the complexities that you see? Any (wild?) guess is welcome.

This is high level, and I would love to get input from the community on what they think. Is this even the right way to go? Would anyone from the community be interested? Would anyone want to cooperate on this? All comments are welcome.

[disclaimer: these are my guesses, I’m not speaking for the team. And I am the least knowledgeable about the code]

Before you start, I suggest experimenting with HTML-like nodes. Even if you don’t like the syntax, can you get reliable results that look the way you want? If not, work with us to try to fix the problems. Then, either declare success or see below.

  • no existing shape has sub-fields for text and/or fill colors. Not an awful idea to enhance the shape concept, but probably a slog
  • instead think of a new label type, like record & HTML. They seem to be good models.
  • lib/common/shapes.c has much of the info you need to think about shapes & record-labeled nodes. (not sure where the HTML code is)
  • when thinking about a model for a new label type:
    • record does not support fill colors or images
    • record cause certain layout problems for “flat” edges between nodes on the same rank
    • HTML seems to support all the features you want, with possible exception of correctly rounded table edges

Possibilities:

  • if HTML works for you, but you dislike the syntax, create a preprocessor outside Graphviz: your syntax-to-HTML and declare success
  • enhance the capabilities of all shapes to support “sub-fields” then add your new shape. This would seem to require additions to the node data structure - extra text fields, extra fill colors, … (guess: a big slog, probably requiring code changes all over)
  • enhance the record (and Mrecord) label type, adding multiple fill colors & image inclusion. (guess: the image inclusion might be a bit of work) (remember the layout issues for records)
  • create a new label type, based on a copy of record (similar to above)
  • create a new label type that would really be a wrapper for the HTML type, just with simpler syntax. You would add the parser for your new syntax, similar to parse_reclbl in shapes.c to translate to HTML.
  • create a new label type somewhat from scratch (slog?)

Did this help in any way?

As recommended by steveroush I think the HTML-like nodes option is the easiest way to go.

All this diagram is practically nodes where the Label is an HTML table.

You can get very close with HTML (see below). The only problem I see is that the fill-color is a rectangle, even if the style is rounded (look carefully at the attached image).
bgcolor works correctly as an attribute of the table (then fill with white for the other fields), but gets messy with images or third fill-colors.

digraph i{
 {rank=same
  n1 [shape=plaintext,label=<
  <TABLE style="rounded" CELLSPACING="0" CELLPADDING="0" BORDER="1" cellborder="0"> 
  <TR><TD FIXEDSIZE="true" height="20" width="20"><IMG  SRC="image_dir/cow.png" scale="true"/></TD><TD>some text<BR/>goes here<BR/>some text<BR/>goes away</TD></TR>
  </TABLE>  >  ]

  n2 [shape=plaintext,label=<
  <TABLE style="rounded" CELLSPACING="0" CELLPADDING="0" BORDER="1" cellborder="0" >
  <TR><TD colspan="2" bgcolor="green1">Step #1</TD></TR>
  <TR><TD FIXEDSIZE="true" height="20" width="20"><IMG  SRC="image_dir/cow.png" scale="true"/></TD><TD>some text<BR/>goes here</TD></TR>
  </TABLE> > ]

  n3 [shape=plaintext,label=<
  <TABLE style="rounded" CELLSPACING="0" CELLPADDING="0" BORDER="1" cellborder="0" >
  <TR><TD colspan="2" bgcolor="green1">Step</TD></TR>
  <TR><TD FIXEDSIZE="true" height="20" width="20"><IMG  SRC="image_dir/cow.png" scale="true"/></TD><TD>some text</TD></TR>
 <TR><TD colspan="2"></TD></TR>
 <HR/>
 <TR><TD >age:</TD><TD >old</TD></TR>
 <HR/>
 <TR><TD colspan="2" bgcolor="lightpink" >Warning: geeky</TD></TR>
  </TABLE>   >  ]
  n1 -> n2 -> n3
  }

n4 [shape=Mrecord label="{Mrecord|and some more\nstuff}" style=filled color=green]
n1 -> n4
} 

Giving:
yaSimpleTable1

There have been numerous requests for new node shapes in the past. E.g. [Dot] Add logic gate shapes (#99) · Issues · graphviz / graphviz · GitLab is one that is repeatedly requested by multiple people. I’m not aware of any current effort to actually address these requests though.

As Steve said, lib/common/shapes.c is the place to look. It even has ASCII art drawings of the existing shapes.

How would we need to test this?

Take a look at tests/test_regression.py. This is a kitchen sink of test cases, with the full expressibility of Python available to you. I imagine you could construct something in here that renders to an output format of your choosing and then somehow programmatically ask “does the rendered image look close enough to my shape?”

I’m not aware of any barriers to adding new shapes (with the exception of the effort required to do so), so I’m supportive of this.

Thank you all for the great input. I am looking to get this one “right”, so the node should look good.

It might be easiest would be to look at how to cut off the filled corners of the HTML table to make it look right.

But I will look into shapes.c as well. Is there a way how to provide a shape with more than one colour if it is defined as a polygon or a record? Or would that require much more work?

I think you can achieve what you need using a combination of existing shapes (rectangle), styles (rounded,filled), and Gradient fill parameters (70% Azure, 30% Blue fill, with a gradient angle of 90 degrees). For example, these attributes:

labelloc="top" shape="rect" height="0.75" width="1.5" gradientangle="90" fillcolor="Azure;0.70:Blue" color="SeaGreen4" penwidth="2" fontname="Arial" fontsize="14" fontcolor="Red" style="rounded,filled"

along with a html-like label such as:

<<b>Heading</b><br/><BR/>Some Text<BR/>More Text>

will create this shape:

image

I’m assuming you can get a more precise layout in the label by using a table, but you get the point.

Shameless plug, this node definition was created using the “Style Designer” worksheet in the Excel to Graphviz Relationship Visualizer spreadsheet.

2 Likes

It might be usefull to add this usage of color gradients in the documentation and sample gallery of graphviz.org. It is not obvious from the current documentation this is possible, but nevertheless very useful.

1 Like