How to put arrows inside of a table and have the table be readable?

Hi,
I’ve tried putting arrows inside of a table with cetz like this:

#table.cell(rowspan:rows)[#canvas({
      import draw: *
      line((),()) // R^0,1
      rotate(180deg)
      set-origin(origin)
      scale(scale_factor)
      line((0,2),(0,3),mark:(start:">",end:">"))
    })]

The problem with this is that it uses one cell for the whole arrow. This way it’s not readable on which height the arrow starts. One could insert hlines in each cetz drawing by hand but this is not optimal.

Does anyone know a way of putting arrows inside of table like shown while still having hlines or something similar that help structuring the table?

Thanks in advance!!!

Hi. You did not provide the specification, nor the compilable example, and how it now stands, the question in the title was already answered.

I tried a bunch, but it all seems very limited.
#table(
  columns: 2,
  align: center,
  table.header()[][123],
  ..range(1, 7).map(body => table.cell(x: 0)[#body]),
  table.cell(rowspan: 6, inset: 0pt, canvas(length: 1.6em, {
    import draw: *
    line((), ())
    line((0, -1), (0, -5), mark: (symbol: ">"))
    line((1, -2), (1, -4), mark: (symbol: ">"))
  })),
)

#let lines(rows: 10, ..coords-list) = {
  table.cell(rowspan: rows, inset: 0pt, canvas(length: 1.6em, {
    import draw: *
    line((), ())
    for (x, start, end) in coords-list.pos() {
      line((x, -start), (x, -end), mark: (symbol: ">"))
    }
  }))
}

#table(
  columns: 2,
  align: center,
  table.header()[][123],
  ..range(1, 7).map(body => table.cell(x: 0)[#body]),
  lines(
    rows: 6,
    (0, 1, 5),
    (1, 2, 4),
  ),
)

#let lines(rows: 10, start: 0, end: 10, ..coords-list) = {
  let rest = rows - (end - start)
  let arrows = canvas(length: 1.6em, {
    import draw: *
    line((), ())
    translate((0, rest))
    for (x, start, end) in coords-list.pos() {
      line((x, -start), (x, -end), mark: (symbol: ">"))
    }
  })
  (..([],) * start, table.cell(y: rest, rowspan: end - start, inset: 0pt, arrows))
}

#table(
  columns: 2,
  align: center,
  table.header()[][123],
  ..range(1, 7).map(body => table.cell(x: 0)[#body]),
  ..lines(
    rows: 6,
    start: 1,
    end: 5,
    (0, 1, 5),
    (1, 2, 4),
  ),
)

A table wrapper looks just right:

#import "@preview/cetz:0.3.4": *

#let lines(rows: 10, start: 0, end: 10, x: 1, ..coords-list) = {
  let rest = start + 1
  let arrows = canvas(length: 1.6em, {
    import draw: *
    line((), ())
    translate((0, rest))
    for (x, start, end) in coords-list.pos() {
      x = x * 0.8
      line((x, -start), (x, -end), mark: (symbol: ">"))
    }
  })
  table.cell(x: x, y: rest, rowspan: end - start, inset: (y: 0pt), arrows)
}

#let arrow-table(column-headers: (), row-headers: (), ..column-arrow-list) = {
  let column-arrow-list = column-arrow-list.pos()
  table(
    columns: column-headers.len() + 1,
    align: center,
    table.header([], ..column-headers),
    ..row-headers.map(body => table.cell(x: 0)[#body]),
    ..column-arrow-list
      .enumerate(start: 1)
      .map(((x, arrow-list)) => {
        lines(
          rows: row-headers.len(),
          start: calc.min(..arrow-list.map(arrow => arrow.at(1))),
          end: calc.max(..arrow-list.map(arrow => arrow.at(2))),
          x: x,
          ..arrow-list,
        )
      })
      .flatten()
  )
}

#arrow-table(
  column-headers: range(1, 5).map(str),
  row-headers: range(1, 7).map(str),
  (
    (0, 1, 3),
  ),
  (
    (0, 1, 5),
    (1, 2, 4),
  ),
  (
    (0, 0, 6),
  ),
  (
    (0, 0, 2),
    (1, 1, 3),
    (2, 2, 4),
    (3, 3, 5),
    (4, 2, 6),
  )
)

Hi! Thanks a lot for the wrapper.

Sorry for (not providing a working example and) not phrasing the question in the title correctly. It should have been “[…] and have the table be readable?” as stated in my post (but not in the title).

What do you mean by “specification”?

Thank you

1 Like

A set of requirements or rules that a solution must follow. Is it supposed to be the exact replica of the screenshot, or not, or something in between? It’s vague.