How to make graphics on math equation?

Hello!

Suppose I want to make something like this:

Where I have an equation, I do a underbrace and then a circle to mark the term and then refer to that circle later. Is this possible in typst? The equation I have included here:

  $ rho ( (Dif bold(u)) / (Dif t) ) = - nabla p + mu (nabla dot nabla)bold(u) + (mu_nu + mu/3) nabla(nabla dot bold(u)) + f_"external" $

Kind regards

1 Like

This is the best I have right now, I feel it is quite complex though:

  + *Momentum Equation*

  $ underbrace(rho ( (Dif bold(u))) / (Dif t), #move(dy: 0pt)[#circle(radius: .8em)[
      #set align(center + horizon)
      I
    ]]
    )
    = underbrace(- nabla p, #move(dy: 6pt)[#circle(radius: .8em)[
      #set align(center + horizon)
      II
    ]]
    )
    + underbrace(mu (nabla dot nabla)bold(u) , #move(dy: 6pt)[#circle(radius: .8em)[
      #set align(center + horizon)
      III
    ]]
    )
    + underbrace((mu_nu + mu/3) nabla(nabla dot bold(u)), #move(dy: 0pt)[#circle(radius: .8em)[
      #set align(center + horizon)
      IV
    ]]
    )
    + underbrace(f_"external", #move(dy: 4pt)[#circle(radius: .8em)[
      #set align(center + horizon)
      V
    ]]
    )
  $

1 Like

That looks like you’re on the right track tho. You can change the clunky feeling of it by putting it all in a function:

+ *Momentum Equation*
#let c(n) = $ #circle(radius: 6pt, align(center+horizon, n))$
$ underbrace(rho ( (Dif bold(u))) / (Dif t), #c[I])
= underbrace(- nabla p, #c[II])
+ underbrace(mu (nabla dot nabla)bold(u) , #c[III])
+ underbrace((mu_nu + mu/3) nabla(nabla dot bold(u)), #c[IV])
+ underbrace(f_"external", #c[V])
$

I changed the radius to be a fixed size, because otherwise the circles would appear bigger if you reference them inside of text, and also removed the move call, as your reference image doesn’t have that either.


So while it doesn’t really change your approach, it just makes it easier to handle

Amazing!

Would anyone have suggestions on how to align the markers vertically automatically? I suppose it should be possible to:

  1. Find the location of each marker
  2. Find the lowest position
  3. Move all the markers to this position

And then one would be sure it aligns, but how? hmm

Kind regards

There are two problems with this: you now need two kinds of markers (the ones that track location inside the equation, and ones that don’t, for referring to them in the text); and the problem of tracking markers in different equations

But your approach is basically what I ended up doing: track the maximum y position for each equation in a state variable, then move each marker to the last tracked position

+ *Momentum Equation*
#let c(n) = $#circle(radius: 6pt, align(center+horizon, n))$
#let mc(n) = context {
  let eq = counter(math.equation).get().first()
  let ypos = here().position().y
  state("maxy"+str(eq), 0pt).update(s => return calc.max(s, ypos))
  move(dy: state("maxy"+str(eq), 0pt).final() - ypos + 2pt, c(n))
}
#set math.equation(numbering: "(1)")
$ underbrace(rho ( (Dif bold(u))) / (Dif t), #mc[I])
= underbrace(- nabla p, #mc[II])
+ underbrace(mu (nabla dot nabla)bold(u) , #mc[III])
+ underbrace((mu_nu + mu/3) nabla(nabla dot bold(u)), #mc[IV])
+ underbrace(f_"external", #mc[V])
$

$
underbrace(a + b, #mc[VI])
$

#lorem(5) #c[I] #lorem(3) #c[II] #lorem(15)

If you want to track multiple equations with this implementation, you’ll need to turn on equation numbering. Alternatively you could also call

#counter(math.equation).step()

by hand between the equations.

1 Like