Jollywatt / typst-fletcher

Typst package for drawing diagrams with arrows, built on top of CeTZ.
MIT License
270 stars 6 forks source link

tikzcd syntax #3

Closed jaroeichler closed 5 months ago

jaroeichler commented 5 months ago

Instead of writing

let (src, img, quo) = ((0, 1), (1, 1), (0, 0))
node(src, $G$)
node(img, $im f$)
node(quo, $G slash ker(f)$)
edge(src, img, $f$, "->")
edge(quo, img, $tilde(f)$, "hook-->", label-side: right)
edge(src, quo, $pi$, "->>")

I'd like

G arrow(r, ->, f) arrow(d, ->>, pi) & im(f) \
G slash ker(f) arrow(ur, ->, tilde(f))

In tikzcd the nodes are put into a matrix environment. The arrows are paths from the current node with a given direction to the target node. Is it possible to do something similar here?

Jollywatt commented 5 months ago

It could very well be possible. So far, I haven't quite figured out a syntax that I think is expressive enough. But here are my current thoughts about it:

  1. It would be nice to use a &-aligned math environment for convenient syntax. There is one hacky way I think this could be done:

    #let edge(..options) = metadata((kind: "edge", options: options))
    
    #let eq = $
    G edge("r", ->, f) edge("d", ->>, pi) & im(f) \
    G slash ker(f) edge("ur", ->, tilde(f))
    $

    If you look at #eq.fields(), you’ll see that the “dictionary-structs” that represent edges are accessible through the metadata elements, so it’s conceivable that this could be translated into an array of nodes and elements, like a normal diagram.

  2. As yet, I’ve not allowed the use of the nodes’ content where a coordinate is expected, but since this is all in math-mode, it might make sense do to that. That would allow things like:

    #fletcher.diagram($
        A edge(A, C, bend: #50deg) & B & C
    $)
    // would be equivalent to:
    #fletcher.diagram(
        node((0,0), $A$),
        node((0,1), $B$),
        node((0,2), $B$),
        edge((0,0), (0,2), bend: 50deg),
    )

    At least then you could form edges between non-adjacent nodes.

Overall, I’m a bit hesitant to make the notation too magical, but I think there’s still something there…

jaroeichler commented 5 months ago

Maybe it's better to use matrix syntax then. At least, it's intended to be used for 2d arrays and should be easier to work with. Also, you should still be able to form edges between non-adjacent nodes

#fletcher.diagram(
  A edge(rr, bend: #50deg), B, C;
)

Another option would be to at least write out rr to (2, 0). This would be closer to the CeTZ sytax of line((), rel: (2, 0)).

This matrix/align notation gets confusing for bigger diagrams though. So maybe it's better to stick to coordinates and shorten the notation there. But I don't think calling nodes by their content is a good idea. You often have maps $A \to A$ or objects that don't make a good variable name like $H^i(X, R)$.

Jollywatt commented 5 months ago

These are good comments. I’ve had a go at making something like this on the tikz-style branch I just added.

On that branch, you can do this:

#fletcher.diagram(axes: (ltr, ttb), $
  G edge(f, ->) edge(#(0,1), pi, ->>) & im(f) \
  G slash ker(f) edge(#(1,0), tilde(f), "hook'-->")
$)

instead of this:

#fletcher.diagram(axes: (ltr, ttb),
  node((0,0), $G$),
  edge((0,0), (1,0), $f$, "->"),
  edge((0,0), (0,1), $pi$, "->>"),
  node((1,0), $im(f)$),
  node((0,1), $G slash ker(f)$),
  edge((0,1), (1,0), $tilde(f)$, "hook'-->")
)

It’s still rough around the edges. (I might have to make axes: (ltr, ttb) the default, instead of (ltr, btt).)

The changes I made were:

Things that are tricky:

Features I’m aiming for:

I welcome any ideas!

Jollywatt commented 5 months ago

This is done in v0.4.0 😃

You can now do:

G edge("r", ->, f) edge("d", ->>, pi) & im(f) \
G slash ker(f) edge("ur", ->, tilde(f))