Fletcher multipart nodes and start/end labels

I want to show a graph of multipart nodes (akin to TikZ multipart nodes) with start and end labels.

Something like this, which I fudged together:

#import "@preview/fletcher:0.5.8" as fletcher: diagram, node, edge

#let mynode(pos, text1, text2, name) = {
  node(pos, [#text1 \ #text(size:0.7em, text2)], name:name, stroke: 1pt, corner-radius: 1mm, 
       height: 3.5em, width:5em)
  /* Dashed separator from east to west */
  edge(label(str(name)+".west"), label(str(name)+".east"),"-", stroke: 0.2mm, dash:(1mm, 0.8mm))
}
#let myedge(start, end, type, startlabel, endlabel, 
            startpos:0.12, endpos:0.88) = {
  let sep = 0.15em
  edge(start, end, type, label: startlabel, label-pos: startpos, label-sep:sep)
  edge(start, end, label: endlabel, label-pos: endpos, label-sep:sep)
}

#diagram(
  edge-stroke: 0.3mm,
  mark-scale: 80%, 
  mynode((0,0), [Fred], $A_1$, <A1>),
  mynode((2,0), [George], $A_2$, <A2>),
  mynode((2,2), [Harold], $A_3$, <A3>),
  mynode((0,2), [Ian], $A_4$, <A4>),
  myedge(<A1.east>,<A2.west>,"-|>", $5$, $7$),
  myedge(<A2.south>,<A3.north>,"-|>", $2$, $3$),
  myedge(<A3.west>,<A4.east>,"-|>", $1$, $6$),
  myedge(<A4.north>,<A1.south>,"-|>", $8$, $4$),
)

It looks more or less the way I want, but feels wrong, because:

  • I’d really like the upper and lower labels to be centered in each part
  • If the node is filled, the dash separator is hidden behind the fill
  • This creates two edges per logical edge (one for each edge label, with only the stroke applied to the start-label edge)

Is there a more idiomatic way to do these things in Fletcher?

1 Like

The requirements seem very similar to my (WIP, not published to Universe) plum.

  • I also use multiple edges to get multiple labels (code example); note that you can use relative lengths such as 5mm & 100% - 5mm for the label position to make the label position not depend on the edge length; requested here

  • for the split nodes, I use a node with a grid label (unexciting code example), then you get all the Typst layout stuff for free. Note that I still use regular node strokes for the outer border, since iirc the grid stroke can’t have a corner radius.

1 Like

interesting… how do you define a function that takes in either a relative length or a float? I’m having value type problems when I try to use the relative lengths

I would probably write if type(value) in (int, float) or if type(value) in (relative, length, ratio) and then handle it from there. If the value is a number, you have to decide which it should be; convert via multiplication: value * 100% or value * 1mm, or something like that.