#Tables
6788 messages ยท Page 7 of 7 (latest)
but i mean, the most important takeaway here is that we need an example showing how to remove vertical lines
wait, so h/vline have the highest priority?
yes
I thought they have the medium priority.
๐
Yeah, but what was the argument for this again?
you cant add hlines / vlines in templates
which templates?
#set table(...)
and #set table.cell(...)
so it's natural that the thing which the user has to explicitly specify at call site will have more priority over things which can be overridden globally
So you are saying that #set table.hline(...) doesn't exist?
it does
but you have to place the hline for it to have any effect
if your table has no hlines that doesnt change anything
whereas #set table.cell(...) and #set table(...) will affect all tables regardless of what you use
It would be cool if you can disable only horizontal lines with the set rule. Which means that the table's rules are affecting vlines and hlines.
I even think now that it is a better approach.
but you can
the thing is that vlines and hlines changed their semantics from what we had thought initially
initially we had defined vline and hline to be any vertical or horizontal line in the table
so indeed hline and vline would have low priority because they're just a basic thing
but after our call we decided that hlines and vlines are only user overrides
the "basic lines" in the table are really just cell strokes
so #table(stroke: ...) sets cell strokes
oh, right.
and so if you want to disable horizontal lines , you can write #table(stroke: (y: none)) for instance
...
I don't know what to say. I'm just impressed.
It's like writing set rule for v/hlines, but in the same place, just chaning x/y.
truly genius. It is much more convenient, but you need to write table/stroke/y/...,x/...
But are those lines override the cell's stroke or create new lines on top?
I think this also was discussed...
it overrides the cell's stroke property
if it doesnt define its own
if cell doesn't define its own stroke?
yeah
what does "define" mean?
table.cell(stroke: red)[a]
define define
think of #grid(stroke: blue, stuff) as
#[ #set grid.cell(stroke: blue) #grid(...) ]
So if you use this, then it will actually have a higher priority than the hline?
there is, because we are talking about placing them
if you place one then the hline has higher priority
so hline overrides cell's stroke if cell doesn't override its own stroke. But if the cell does override its own stroke, then hline will still have a higher priority.
that's how I interpreted your words.
i meant that #grid(stroke: ...) sets the cell's stroke field
unless you set it manually, then it doesnt
and regardless of that
grid.hline and grid.vline will appear on top
[0m[3m[34m#table[0m(
columns: [0m[33m3[0m,
[], [], table.[0m[3m[34mcell[0m(stroke: green)[hey],
table.[0m[3m[34mhline[0m(stroke: red),
table.[0m[3m[34mcell[0m(stroke: green)[hey], [], [],
)
Indeed...
So, I'm guessing that for simple tables if you don't want to override, you just add start/end. And for complex tables you are on your own, probably have a complex show rule for everything as well.
I don't usually change hlines, but it is something that I will need to experience myself to know if it's good or bad.
I feel like begin/end is a more iconic duo and h/vline should use it instead of start/end. Because normally it's start/stop.
it's analogous to the line parameters
indeed
https://staging.typst.app/docs/reference/model/table/#definitions-hline-stroke:
The line's stroke.
Specifying
noneinterrupts previous hlines placed across this line's range, but does not affect per-cell stroke or vlines.
What does interrupts previous hlines mean? It does affect per-cell stroke:
#table(
columns: 3,
[], [], table.cell(stroke: green)[hey],
table.hline(stroke: none),
table.cell(stroke: green)[hey], [], [],
)
oh yea good catch
laurenz asked me to change that i think but i forgot to update the docs
which metadata?
i assume that was intentionally unspecified as it wasnt implemented yet
but in general, something that indicates what the header of your table is
And what difference will it make? For clarity?
for accessibility
I know that
so maybe a screen reader will say "table header"
well we cant really reason about it as it doesnt exist
it's just a vague suggestion to use it whenever something of the sort is added
I assume martin had PDF-A in mind when he wrote that
or something like that
it isn't implemented, but it must exist already, otherwise this whole vague stuff is useless.
why is it useless?
it's just encouraging people to future-proof their stuff
pretty normal
if the thing doesn't exist, then there is no point in planning to add it.
why not?
Because we don't know what will happen in the future. otherwise we need to predict 100 stuff that might be created and then added in the typst.
that sounds like a strawman though
it's not saying to prepare yourself against 100 unpredictable stuff
it's saying to prepare yourself against one specific thing which is planned and will be added
I thought there is some kind of standard, but if it's nothing, then our standards are bad, this should've been existed for a long time.
there is
i mean there are PDF standards
it's probably just gonna use one of them
i just cant tell you cuz i dont speak PDF
so the info i have is very limited
it didnt exist before cuz table headers didnt either
now that they do, we can begin to consider implementing this
anyway
planned and will be added to the standard?
i cant give much more info
no, the standards already exist, typst will just conform to them
also for example, when html export becomes a thing
a table header would be exported as <thead>
no, the standards already exist, typst will just conform to them
so the "something that indicates what the header of your table is" does exist after all. But you've said that it doesn't exist just a moment ago.
with "it" i meant the typst implementation
anyway, this answer explains it better https://stackoverflow.com/a/53598697
how fragile the language is sometimes...
telepathy when?
do you really can't combine them?
sad
well, or
#show table.cell: it => {
if it.x == 0 or it.y == 0 {
strong(it)
} else {
it
}
}
I guess the only way is to add new syntax where(x: 0 or y: 0) or make where(x: 0).or(where(y: 0)).
so basically tell typst to use where for the same thing as in the first time.
Wait, if you import cell, do you do #show cell.where().or(cell.where())?
sure
well, this is much better.
No other table cells may be placed after the footer.
even if you specify the cell's position as above the footer?
in that case it's fine
mMm
so, are you on it?
done
now it makes all sense.
I wanted to move out euro to make the table extra cool, but apparently I can't even do that properly:
// #set table.cell(stroke: green) // works
#set table.cell(inset: (right: 0pt)) // works
#show table.cell: it => {
// set table.cell(stroke: green) // doesn't work
if it.x > 0 and it.y > 0 {
set table.cell(inset: (right: 0pt)) // doesn't work
// set table.cell(inset: 0pt) // doesn't work
align(it.align, box(it) + box(inset: it.inset + (left: 0pt, right: 5pt))[#sym.spaceโฌ])
} else { it }
}
#table(
fill: (col, _) =>
if calc.odd(col) { luma(240) }
else { white },
align: (col, row) =>
if row == 0 { center }
else if col == 0 { left }
else { right },
columns: 4,
[], [*Q1*], [*Q2*], [*Q3*],
[Revenue:], [1000], [2000], [3000],
[Expenses:], [500], [1000], [1500],
[Profit:], [500], [1000], [1500],
)
Why is the local set rule doesn't work? it is illegal, isn't it?
Also normal space is ignored there, so instead of becoming extra cool, it becomes extra ugly.
See the changelog on styling
It doesn't answer the first question.
moreover, I need to know how to overcome this limitation to achieve the goal, which is pretty reasonable, but hacky nevertheless.
If I was able to modify the it.body, then it would all be fine, but I can't.
#let eurotable(columns: auto, euro-cols: none, table-func: table, ..args) = {
if type(euro-cols) == int {
euro-cols = (euro-cols,)
}
assert(euro-cols == none or type(euro-cols) == array and euro-cols.all(x => type(x) == int))
let cells = args.pos()
let opts = args.named()
let c = if type(columns) == int {
calc.max(columns, 1)
} else if type(columns) == array {
calc.max(columns.len(), 1)
} else {
1
}
cells = cells.enumerate().map(((i, cell)) => {
let cell-func = if type(c) == content { c.func() } else { none }
let cell-x = if cell-func == table-func.cell and cell.x != auto { cell.x } else { calc.rem(i, c) }
let cell-y = if cell-func == table-func.cell and cell.y != auto { cell.y } else { calc.floor(i / c) }
if euro-cols != none and cell-func not in (table-func.footer, table-func.header, table-func.hline, table-func.vline) and cell-x in euro-cols and cell-y > 0 {
let fields
let body
let label
let cell = if cell-func == table-func.cell {
fields = cell.fields()
body = if "body" in fields { fields.remove("body") }
label = if "label" in fields { fields.remove("label") }
} else {
fields = (:)
body = cell
label = none
}
[#table-func.cell([#body โฌ], ..fields) #label]
} else {
cell
}
})
table-func(..cells, ..opts, columns: columns)
}
#eurotable(
euro-cols: (1, 3),
fill: (col, _) =>
if calc.odd(col) { luma(240) }
else { white },
align: (col, row) =>
if row == 0 { center }
else if col == 0 { left }
else { right },
columns: 4,
[], [*Q1*], [*Q2*], [*Q3*],
[Revenue:], [1000], [2000], [3000],
[Expenses:], [500], [1000], [1500],
[Profit:], [500], [1000], [1500],
)
you can't mutate read-only variables.
wut?
missing let euro-cols = euro-cols
does it error if you run the code?
if you change the type of the argument when you call the function
Does it error then?
Pretty sure it would.
There's only one way to find out
Haha
But in principle it shouldn't
You aren't attempting to mutate an external variable
Euro-cols is an internal variable
You would have an error if it were an array and you tried to append to it
But here we're replacing its contents entirely
hmm, strange. did all my previous errors were due to a different use case...
This is truly a work of art, but not only changed the table name, but also there are new arguments. typst-lsp wouldn't handle it. I want table. Native one.
So you basically reconstructed the table cell from its pieces into a new table cell, which I wanted to do, but in show rule this will fail due to recursion.
I assume, since you've made a big-ass function instead, there is no way to do it properly with a single show rule.
i think one possible idea to make table styling easier could be to synthesize table properties
e.g. replace the (auto, auto) columns by (1pt, 2pt)
even table.children could theoretically be synthesized
but in practice i feel like that would be harder to get right
is this related to the not working show set thing?
no
it's just a feature idea
being able to show table and have access to the final sizes of columns and rows
And now you can't?
no, table fields in show rules will be almost exactly as you specified them
columns will be changed from 2 to (auto, auto) for example
but not much more than that
yeah, shame
also
i found a good use case for a fit parameter for cells, to have them not affect auto rows
basically being able to have some line as large as the adjacent content, like block(stroke: ...) but with more flexibility
so you'd be able to have anything as large as adjacent content
while it would be very quick to implement that, theres of course no time to add it to this release, so we can discuss for 0.12
personally i think it'd bring value, much like fit-spans in tablex, but I'm open to hearing other opinions about such a feature
ok i just implemented it
looks cool
basically easier way to make stuff have the same height as other stuff
without having to measure()
or same width
well the grid does measure internally but you dont need to know that
anyway but that'll be for 0.12 so i don't wanna give it too much importance
I might open a draft PR later just in case
Okay
@robust viper i found a bug (or, at least, inconsistency) in tables
TL;DR:
#table(
rows: 2em,
block(width: 2em, height: 100%, fill: red)
)
Produces a small block,
But wrapping it in a rowspan: 2 table cell causes it to go all the way to the end of the page
Luckily not a regression though
That's true, though it's worth considering
Basically I'm just using the region full from the first region the rowspan appears in, ideally i should change that :p
the rowspan behaviour seems more correct
ah no
nevermind
didn't see the rows: 2em
yeah
In theory it's a quick fix, we just need to determine the criteria for using or not the first region full
Maybe spans auto row = yes, doesn't = no?
seems sensible
I think unbreakable cell = no as well for consistency
As an unfortunate consequence of measuring with infinite height, an unbreakable auto row won't pick up 100% properly
So yeah
Anyway
I'll take a look at this in a few hours, once I'm at my PC
Should just be a simple "if" in layout_rowspan
I really like the tables.
#let spin(word,origin,length) = {
return (
table.cell(colspan:length,x:origin.x,y:origin.y)[#word],
table.cell(rowspan:length,x:origin.x+length,y:origin.y,rotate(90deg,reflow:true)[#word]),
table.cell(colspan:length,x:origin.x + 1,y:origin.y+length,align:right,rotate(180deg,reflow:true)[#word]),
table.cell(rowspan:length,x:origin.x,y:origin.y + 1,align:bottom,rotate(270deg,reflow:true)[#word])
)
}
#table(columns:8,
..spin([TABLES],(x:0,y:0),7),
..spin([TABLES],(x:1,y:1),5),
..spin([TABLES],(x:2,y:2),3),
table.cell(rowspan: 2,colspan: 2,x:3,y:3,align: center+horizon)[#emoji.star]
)
An error occurred:
Error: function `table` does not contain field `cell`
โญโ[/main.typ:10:11]
โ
10 โ table.cell(colspan:length,x:origin.x,y:origin.y)[#word],
โ โโโโ
โ
โโโโโฏ
They work good even when nesting.
I don't understand what is happening, but this is impressive.
Someone just ran into this: #1217143831926145154 message
Seems like there's a use case here
I'll be working on this soon, just got home
It's kinda funny how many bugs I find out by just reflecting about things lol
In particular i was thinking about the feature i mentioned above, of having cells fit within auto rows without expanding them
And then i thought well i wonder if there would be any problems in implementing this on rowspans
And then i thought ... Wait ... Lol
Anyway , but even then, I'm happy that we haven't rlly been facing any major bugs
Even though lots of complex stuff has been added
So yay
forgot to comment on this but lol, very epic
nice to see that you're enjoying the new tables ๐
so i found a weird thing here i get an error if i have less than 15 columns:
#table(columns:15,
..range(0,10).map(y => {
range(0,10).map(x=>{if calc.rem(x,2) == calc.rem(y,2) {table.cell(rowspan:2,x:x,y:y,[#x])}else {} })
}).flatten()
)
and whats that error?
attempted to place a second cell at column 9 row 1.
ehh it changes depending on the number of columns..
the hint is very helpful
i suggest reading it
๐
as explained here
you're placing cells with manual positioning followed by one cell with automatic positioning (from the else {}) followed by more cells with manual positioning
so the latter cells wont be aware of that one cell with automatic positioning
and can potentially try to overlap with it
anything in the table is a cell
none is converted to [] which is later converted to table.cell[]
with all arguments set to their default values
solutions:
- manual positioning in all cells
- place all manually positioned cells before automatically positioned cells
- use
flat_mapinstead ofmap
flat_map ๐
actually you dont need to flat_map since you already flatten
so you can do the following
if stuff { (table.cell(...), ) } else { () }
array of size 1 vs array of size 0
the latter wont create a cell
ohhhh. so () is more none than none is. this is very helpful.
well
the thing is that you're using flatten
and flatten will replace all arrays by the items inside them
recursively
yeah i was trying to filter but i was too noob.
so it will convert ( (...), (...), (...) ) to (..., ..., ...) and then the arrays inside those to their items
but () has no items
so
it's just ignored
Hi. I did not follow the table changes very closely, so I assume this is a known limitation, but is there a way to style table headers? For example, I would like to do the following:
#show table.header: set text(weight: "bold")
But this does not work.
I'm sorry if this was already answered, I was unable to find recent information about that.
Yeah it's known
Unfortunately won't happen for the next version
Though
I'd suggest opening an issue on it
Just so i don't forget
๐
I'll do that
(feel free to ping me there)
Yeah that'll work for the simplest use cases (though not for arbitrary headers)
Yeah I will use this solution in the mean time, but it's not perfect
I saw at least one or more examples of how the table headers were bolded in the docs. I think there are another ones too.
The table header element can occupy more than one row
And you can't rlly know how many rows it occupies without access to internals ATM
But I guess you can hack something on #show table like I did for the euro column
Either way ideally you'd use #show table.header: ... And it'd just work
At least show-set
normal show won't work cuz headers don't actually exist
They're an illusion of the senses
Mere mortals do not understand the complex power living therein
Ty โค๏ธ
Btw @robust viper
Just wanted to mention that the last case in the draft PR i opened is more of a consequence of the workarounds needed to make the rather "exotic" case of breakable rowspans over unbreakable auto rows "work"
Presently, they are measured with infinite height at the region of the auto row, but this isn't really the best thing
So I'll just apply a workaround to make the case listed in the PR work for now (if the unbreakable auto row occurs at the first region of the rowspan, and the rowspan only occupies one region, we also layout the rowspan with infinite height), and in future versions we can study if there's a better way around this weirdness (maybe a way to not have to use infinite full height for the rowspan if it's breakable after all)
Don't really wanna delay anything so i think this will be the best way forward, I doubt this will be a common case anyway, just don't want users to think tables are broken :p
(for clarification on the problem, check the last page of the updated test in the PR - one of the cells overflows)
actually, can it be a problem to have full height be infinite but remaining height be finite? ๐ค
i guess that's normally weird
haha
?r ```
#import "@preview/tablex:0.0.8": *
#tablex(
[hi] + block(height: 100%, width: 2em, fill: red)
)
okay tablex has a similar problem
lol
the main thing is that 100% and ratios / relative lengths using ratios in general mean different things when measuring and when laying out, within the context of unbreakable auto rows
anyway
i think we can more or less accept at that unbreakable auto rows - a totally new feature - are more of an experimental thing and just move along
i'll undraft the PR soon
@wary knot i previously had a table without any content to show a caro grid as background for my worksheets. With the new table implementation i need to add content with ..("",) * rows_count * cols_count that the table is shown. Otherwise it won't print anything. Is this intended behavior?
i believe it should be enough to write table.cell(y: rows_count - 1)[]
in principle we didnt make any sort of explicit decision on that matter
are you sure it wasnt already like that?
#let caro(rows, cols:auto) = {
layout(size => {
let cols = if( cols == auto ){ int(size.width.cm() / 0.5) } else { cols }
table(
columns: (0.5cm,) * cols,
rows: (0.5cm,) * rows,
stroke: 0.3pt + luma(140),
)
})
}
this was my previous function and it did work.
Now i added the line mentioned above, then it works again
Your solution works as well.
I guess your solution might be a bit better, performance wise?
yours would be equivalent , normally
ok i tested in #bot-corner and it seems the previous behavior wasnt very reliable
ill see what i can do
Anyway, i would have expected if i define a certain amount of rows, that they will all be printed, even if no content is available.
But the current solution is fine for me as well. ๐
okay
I see what changed that caused this
to be honest im not rlly sure what would be the best thing to do here
for one, it does make sense for it to respect the rows you specified
but for another, specifying more rows than we were given is useful for templates for e.g.
being able to specify the sizes of rows if they are actually used
still, restoring this behavior would likely be quick to do
and probably should be done to avoid breaking changes like in your case
although something will certainly change since now you will have actual cells in those rows
they wont be truly empty anymore
but thats probably an acceptable compromise
either way, thanks for letting me know
PR opened: https://github.com/typst/typst/pull/3644
thanks for reporting ๐
@wary knot I checked the PNG files and if a new test is added to a reference at the bottom, most of the binary contents are the same, which should allow git to do a binary delta-coding. As long as the image's width doesn't change and PNG keeps using the same encoding strategy, that means sort of efficient diffs might be possible. This relieves some of the pressure regarding reference images because otherwise just the most recent bug fix PR would have been 240KB added stuff. Still, switching to a hash-based test runner is one of my top priorities for after 0.11.
Maybe we can also use this opportunity to add pdf and svg Tests?
But we would need to make it easy to update new ref images and view the difference
That was also my thinking
And that is indeed the main challenge
I'll open a new forge, give me a minute
I am generating a few options for table strokes for the docs guide. It occurred to me that we maybe want to allow set operations on strokes. I got the idea when I talked about the example with Laurenz and he was like I'd do the union between this one and that one. With set operations, packages or the core could export a few strokes which the user could then match to their desire. @wary knot do you think that would be a good feature for the compiler? https://github.com/typst/typst/issues/3636 may also be relevant (cc @runic oasis)
For comparison, here are all the table stroke functions I wrote for this demo:
#let af(x, y) = (
left: if x > 0 { 0pt } else { 1pt },
right: 1pt,
top: if y == 0 { 1pt } else { 0pt },
bottom: 1pt
)
#let nf(x, y) = (
left: if x > 0 { 1pt },
right: 0pt,
top: if y > 0 { 1pt },
bottom: 0pt
)
#let vertical-vf = (x: 1pt, y: none)
#let vertical-nf(x, _) = if x > 0 { (left: 1pt) }
#let vertical-af(_, y) = (
x: 1pt,
top: if y == 0 { 1pt } else { 0pt },
bottom: 1pt
)
#let horizontal-hf = (y: 1pt, x: none)
#let horizontal-nf(_, y) = (top: if y > 0 { 1pt })
#let horizontal-af(x, _) = (
y: 1pt,
left: if x == 0 { 1pt } else { 0pt },
right: 1pt,
)
#let flb-af(x, y) = (
left: if x == 0 { 1pt } else {ย 0pt },
right: 1pt,
top: if y <= 1 { 1pt } else {ย 0pt },
bottom: 1pt,
)
#let flb-nf(_, y) = (
bottom: if y == 0 { 1pt },
)
#let flbh-af(x, y) = (
left: if x == 0 or y == 0 { 1pt } else {ย 0pt },
right: 1pt,
top: if y <= 1 { 1pt } else {ย 0pt },
bottom: 1pt,
)
#let flbh-nf(x, y) = (
left: if x > 0 and y == 0 { 1pt } else {ย 0pt },
bottom: if y == 0 { 1pt },
)
#let flb-h-af(x, y) = (
left: if x == 0 or y > 0 { 1pt } else {ย 0pt },
right: 1pt,
top: if y <= 1 { 1pt } else {ย 0pt },
bottom: 1pt,
)
#let flb-h-nf(x, y) = (
left: if x > 0 and y > 0 { 1pt } else {ย 0pt },
bottom: if y == 0 { 1pt },
)
#let flbh-h-af(x, y) = (
x: 1pt,
top: if y < 2 { 1pt } else { 0pt },
bottom: 1pt,
)
#let flbh-h-nf(x, y) = (
left: if x > 0 { 1pt } else {ย 0pt },
bottom: if y == 0 { 1pt },
)
Got it
I'll leave my thoughts in the forge thread later
Well, you can already union by just appending the lines at the correct positions
As in ..lines
I'm not rlly sure what you would use the other set operations for, a use case would be best to evaluate that imo
That forces you to adjust the table itself though. This was more about simplifying stroke configuration in global styling.
Not sure if it is ready yet, but the documentation for the first shown table is wrong here: https://staging.typst.app/docs/reference/model/table/#definitions-cell (code != image)
Well... Maybe we need to make #set table(line1, line2, line3) work ๐
Lol but yeah i see what you mean
Though in principle it sounds a bit intrusive or possibly inconsistent to modify all tables like that
Or at least you'd still have to predict the size of the table
So it sounds more practical to make table generator functions than to use show / set rules
Yeah I've commented on this before
Personally I'm in favor of changing that somehow, either changing the example or having something simple enough to be able to include all of the code
I'd prefer simplifying the example then
Because the current code is too noisy
Sounds fair to me
We could use headers to demonstrate colspan
And just have a very simple table like that
Alright, there's one more thing i wanna fix
Though it's not urgent
So I'll work on it today but it's not a blocker if I don't finish it in time
But basically the footer thing where we move to the next row after the latest auto cell isn't really that smart, since it's possible that the next row will also be occupied
Ideally we'd skip until we found a suitable position for the footer
i.e.
#table( columns: 2, table.cell(rowspan: 2)[a], table.cell(rowspan: 2)[b], table.footer() )
will error cuz it will try to place the footer at the second row instead of the third
But anyway it's not that bad, i think adding a single auto cell to the footer makes the error go away so
This mostly just affects lines and stuff really
ok ive fixed it in the new PR
the problem wasnt exclusive to empty footers, so it was worth a fix
anyway , hopefully this will be the last PR with adjustments and stuff before 0.11
:p
because there surely are no more bugs!!! ๐
Is it desired that the header is affected by row-gutter?
#set page(width: 15cm, height: auto, margin: 1cm)
#table(
columns: (1fr, 1fr, 1fr),
stroke: none,
row-gutter: 0.25cm,
table.hline(stroke: 2pt),
table.header([Header 1], [Header 2], [Header 3]),
table.hline(),
[Cell 1A],
[Cell 2A],
[Cell 2A],
[Cell 1B],
[Cell 2B],
[Cell 2B],
[Cell 1C],
[Cell 2C],
[Cell 2C],
table.hline(stroke: 2pt),
)
Table with `row-gutter` set to `0.25cm`
#v(1cm)
#table(
columns: (1fr, 1fr, 1fr),
stroke: none,
table.hline(stroke: 2pt),
table.header([Header 1], [Header 2], [Header 3]),
table.hline(),
[Cell 1A],
[Cell 2A],
[Cell 2A],
[Cell 1B],
[Cell 2B],
[Cell 2B],
[Cell 1C],
[Cell 2C],
[Cell 2C],
table.hline(stroke: 2pt),
)
Table with default `row-gutter`
Yes, for consistency
You can remove the row-gutter below the header by setting it to 0pt
row-gutter: (0pt, 0.25cm)
Of note, what you have there is a line above the row below the header and not a line in the header itself
For that you'd need to use position: bottom on a line above the last row of the header
Cuz when there's gutter you have two possible positions for a hline: above and below a row (read the docs on hline.position for more info)
Ok, thanks for the quick response. Is there a possibility to remove the little inset left of the first column?
Thank you, this works
There sure is a lot to document about tables -- the section on strokes in the WIP table guide alone fills almost 8 screens on my computer!
You have more than 8 monitors? ๐
I'm a bit of a Wall Street Trader myself
Me on my Bloomberg Terminal
Wow lol
We should probably try to keep it as concise as possible, don't want people to just look at the sheer length of the guide and retreat ๐
But I think a clarification at the beginning that the guide covers various use cases and they should look for their use case could be helpful
oh hey
just saw the guide was merged
I'll take a quick look if y'all don't mind
I'll let you know if I have any comments
I'm currently preparing the release, so I'm afraid comments won't make it in anymore. :/ But I reviewed and edited the guide carefully, so I think it should be okay.
ah okay
no problem
I see now that there were indeed a few iterations
I'll trust you ๐ซก
It's also very comprehensive, so it would likely take you a while to review
fair enough, didnt realize we were so close to release haha
anyway , just keep it up then ๐
changing the topic a bit, overall I think the pre-release was very successful
we did indeed find and squash some important bugs so that's cool
so many bugs were captured..
yep
yeah indeed
The guide is super nice ! I havenโt played with it but it looks like we can set booktabs-like for all document ? If so, that would be a nice example in the doc
Do you have a picture of the style you're looking for?
(Just for reference ๐ )
Iโve stealed somewhere this setup used here https://typst.app/project/pF-FdwYCg-fO6GcrAV9-DK (sorry am on mobile cannot get a MWI)
Ah
There was an example on this in this thread
Discord mobile is horrible for threads so I can't search lol
#let toprule = hlinex(stroke: (thickness: 0.08em))
#let bottomrule = toprule
#let midrule = hlinex(stroke: (thickness: 0.05em))
#figure(
gridx(
columns: 2,
[Catรฉgorie], [Mรฉtrique],
toprule,
[รchantillon], [Concentration ADN],
midrule,
[], [Quantification de la librairie],
bottomrule
))
Something like this
Yeah it's possible
Here you'd basically have a rowspan of 2 at the top left, then a colspan of 3 with the tol = thing, and another colspan of 3
The rest would be normal cells
Regarding lines, you'd have three table.hline() calls, at the top , middle and bottom
And the two colspans of 3 would have โstroke: (bottom: 0.5pt + black)โ
The global table stroke would be set to none
Iโm only interested in the hlines (toprule, midrule and bottomrule defined above) ๐
Thatโs what I thought from the doc but havenโt got access to internet to test it yet. That would be great ๐
for the spacing between columns, you can use column-gutter
Here the choice of table.hline vs stroke: (top: ...) matters
Hlines can cross gutter , while stroke goes around cells, so it can't
Interesting
...
#let colspan(n, ..args) = table.cell(colspan: n, ..args)
...
#table(
...
table.header(
[Team member], [Monday], [Tuesday], [Wednesday], [Thursday], [Friday]
),
[Evelyn Archer], colspan(2, ofi), colspan(2, rem), ofi,
[Lila Montgomery], colspan(5, lea),
[Nolan Pearce], rem, colspan(2, ofi), rem, ofi,
)
lt was such a great example to import cell or even better: a custom function that will shrink down horizontal space even further.
i think it's fine
^
there's an example which mentions importing so i think thats enough
importing still wouldn't be short enough to make 1 row per line.
this is redundant.
My gut would say "get x n times", so I would've written 5 the last. That's how I write everything, and I think that is how others also write.
well...
im sorry but we're being way too nitpicky at this point :p
to be honest im probably not gonna look at these docs again (with the eyes of a reviewer at least) for a good several days
let's rejoice , for the release has come forth
๐
If you have placed your table inside of a figure, it becomes unable to break across pages by default. However, you can change this behavior. Let's take a look:
this brings the question: why is figure's block is not breakable by default? is block globally not breakable?
I expected the last part to be "ever".
this wouldnt be desirable for most figure kinds
the idea is to display some stuff with a caption right below it
so most of the time you don't want it to span a pagebreak
well, i wouldnt be saying the truth then :p
I expected the last part to be "ever", judging how the sentence is started.
I can nitpick while being happy that the new version has released.
bruh, I thought I didn't send the message, but only now realized that I did. All because Ctrl+W closed the damn tab again..
ohh, because it can break apart the body and the caption?
oh, no, the proprietary software from micro and soft mentioned. A sad reality...
Why would you complicate the example with unnecessary destruction when you can slice 2 instead?
...slice(2)...
let (year, count) = m
m isn't the one being sliced here though
m is literally the result of the slice.
no
this isn't Rust lol
slice doesnt return Option<T>
to put it more clearly: moore is a list of lists
you removed one list
the header
Typst differentiates between grids that are for layout and presentational purposes only and tables, in which the arrangement of the cells itself conveys information.
I wanted to say that double "and" isn't a good thing, and I tripped over this sentence as an example of why it is bad.
ahhhhh, I thought it removed the first column...
yeah, then it's fine.
I didn't get the reference (no, this isn't a pun, unfortunately).
lol
i thought you were confusing .map with Option::map or smth
since m is clearly not the list itself
but an element in it
but yeah i mean it happens
option map??? whaat? haha Have I missed something in the basics?
ye but anyway, does the text mention that it's skipping a header? If not, it should, sure
I only have a strong connection with map being applied on list only
In this example, we first drop the header row from the data since we are adding our own.
Phew, finally finished half-skimming through the guide. It's great but veeeeeeeery long. I already asked a bunch of time "where is the end?" and "it's still going?!"
I already remembered that it contains a bunch of nice snippets for different styling of a table. Good stuff. Now I or (more realistically) other user wouldn't have to be smart by making those conditional strokes/fills. Just copy and use it.
It is very long indeed, but it's also not necessarily meant to be read in full. You can just skip to the relevant section when you need the thing it explains.
It literally has guide in the name. afaik the guides are for guiding the newcomers or something, so if I'm not mistaking you are supposed to read it full.
Guide can mean many things.
A User Guide isn't supposed to be read in full prior to usage.
example: https://pandoc.org/MANUAL.html. I've rarely met folks who've read this beautiful thing in full, yet all use pandoc.
yeah, here you are right.
I mean it's small enough to be manageable to read in one sitting, so... yeah.. but not really.
@robust viper Are thumbnails on packages.typst.org public? For example, https://packages.typst.org/preview/thumbnails/charged-ieee-0.1.0-small.webp .
This should probably go into #contributors.
wdym with public?
sorry, I posted to the wrong channel.
Ah, yes, finally I can add
[0m[35m#let[0m [0m[3m[34mtable[0m([0m[36m..[0margs) [0m[36m=[0m [0m[3m[34mtable-old[0m(
[0m[36m..[0margs.[0m[3m[34mnamed[0m(),
[0m[36m..[0margs.[0m[3m[34mpos[0m().[0m[3m[34mmap[0m(x [0m[36m=>[0m [0m[35mif[0m [0m[3m[34mtype[0m(x) [0m[35min[0m (int, float) [[0m[37m#x[0m] [0m[35melse[0m { x }),
)
to the native tables and add pass numbers to it.
can't you just use ..args.pos().map(x => [#x])?
it should be equivalent, no?
positional would be also table.cell etc.
oh, right
The problem with that is now all the table.* things are broken and I either have to import them or use table-old.* instead. Not ideal...
yea i'd suggest giving it a different name
This will kill field autocompletion.
you can define a number of named arguments yourself: #let num-table(columns: auto, column-gutter: auto, ..args)
Well then it wouldn't be as neat as it is now, now would it? Plus the descriptions will be gone. And I would have to have this massive snippet saved somewhere, because there is no way I can recreate it from scratch and remember all the fields from my memory, unlike the example I showed. Actually, this is a good point, I should add a snippet for it.
honestly, I would consider the auto completions where there is an overriding let table a bug
true
until we can make a full-fledged copy will all the fields, description etc. while having a different function name, this is the only hack we have. So, waiting for the typed parameters + doc comments.
If kinda tall cell doesn't fit on the page will it be fully placed on the next page or only partially?
Because it does the second option and repeating header is inserted in between the cell's content. I think that's a bug.
The "keep caption with table" hack when overriding a figure show rule for table was causing that. But removing figure, it still happens.
[0m[35m#let[0m leading [0m[36m=[0m [0m[33m1.5em[0m
[0m[35m#let[0m leading [0m[36m=[0m leading [0m[36m-[0m [0m[33m0.75em[0m [0m[30m// "Close enough normalization"[0m
[0m[35m#set[0m [0m[3m[34mpage[0m(margin: (left: [0m[33m3cm[0m, right: [0m[33m1cm[0m, y: [0m[33m2cm[0m))
[0m[35m#set[0m [0m[3m[34mblock[0m(spacing: leading)
[0m[35m#set[0m [0m[3m[34mpar[0m(leading: leading)
[0m[35m#set[0m [0m[3m[34mtext[0m(size: [0m[33m14pt[0m, lang: [0m[32m"ru"[0m)
[0m[35m#import[0m table: hline, header
[0m[35m#let[0m [0m[3m[34mhead[0m(text, stroke: [0m[33m0pt[0m) [0m[36m=[0m ([0m[3m[34mstrong[0m[[0m[37m#text[0m:], [0m[3m[34mhline[0m(stroke: stroke), [], [],)
[0m[3m[34m#v[0m([0m[33m22cm[0m)
[0m[3m[34m#table[0m(
columns: ([0m[33m9cm[0m, [0m[33m2.5cm[0m, [0m[33m1.5cm[0m),
align: (x, y) [0m[36m=>[0m [0m[35mif[0m y [0m[36m>[0m [0m[33m0[0m [0m[35mand[0m x [0m[36m==[0m [0m[33m0[0m { left } [0m[35melse[0m { center [0m[36m+[0m horizon },
[0m[3m[34mheader[0m([ะะฐะธะผะตะฝะพะฒะฐะฝะธะต], [ะงะธัะปะพ ัะปะตะผะตะฝัะพะฒ ะดะฐะฝะฝัั
], [ะ ะฐะฝะณ]),
[0m[36m..[0m[3m[34mhead[0m[ะะฝัััะตะฝะฝะธะต ะปะพะณะธัะตัะบะธะต ัะฐะนะปั],
[
[0m[36m+[0m ะขะฐะฑะปะธัะฐ "ะะพะฒะตัะตะฝะฝะพััะธ"
[0m[36m+[0m ะขะฐะฑะปะธัะฐ "ะะพะฒะตัะตะฝะฝัะต ะปะธัะฐ"
[0m[36m+[0m ะขะฐะฑะปะธัะฐ "ะัะณะฐะฝะธะทะฐัะธะธ"
[0m[36m+[0m ะขะฐะฑะปะธัะฐ "ะะฐัะตัะธะฐะปั"
],
[
10[0m[36m--[0m15
< 10
< 10
< 10
],
)
Not only does the second header add itself in the middle of the cell/row, but it doesn't add the hline for itself, like it always should.
You added an empty hline above the cell being split
It overrides the cell stroke below the header
You can add an hline below the header if you'd prefer for it to win
It's intended.
You can use table.cell(breakable: false) if you would like for it to not be broken apart
I would've never thought of that. Strange, but it works and that at least fixes half of the problem.
Well we were trying to conciliate multiple requirements here so it was a bit hard
We want hlines to win but we want headers to have priority
So we made header strokes have priority over cell strokes , but not over hlines
Yeah, that fixes the second half.
But header hline will always appear
Well, at least now I know how to deal with such problem. Thanks.
np
Feels like a bug:
?r
[0m[35m#let[0m [0m[3m[34mcolspan[0m(n, body) [0m[36m=[0m table.[0m[3m[34mcell[0m(colspan: n, body)
[0m[35m#show[0m table.cell.[0m[3m[34mwhere[0m(y: [0m[33m0[0m): [0m[35mset[0m table.[0m[3m[34mcell[0m(align: center)
[0m[35m#show[0m table.cell.[0m[3m[34mwhere[0m(y: [0m[33m0[0m): it [0m[36m=>[0m {
[0m[35mshow[0m table.[0m[3m[34mheader[0m: [0m[35mset[0m table.[0m[3m[34mcell[0m(align: center)
it
}
[0m[30m// #show table.cell.where(colspan: 2): set table.cell(align: center)[0m
[0m[30m// #show table.cell.where(colspan: 2): it => {[0m
[0m[30m// show table.header: set table.cell(align: center)[0m
[0m[30m// it[0m
[0m[30m// }[0m
[0m[3m[34m#figure[0m([0m[3m[34mtable[0m(
align: (left [0m[36m+[0m horizon, left, center, center, center),
columns: ([0m[33m2.5fr[0m, [0m[33m1fr[0m, [0m[35mauto[0m, [0m[35mauto[0m, [0m[35mauto[0m),
table.[0m[3m[34mheader[0m([0m[3m[34mcolspan[0m([0m[33m2[0m)[A], [B], [C], [D]),
[],
[],
[],
[],
))
how to center content of a *spanned cell? not inline
You can't use show set with table cells or headers or footers or lines
I'm extremely aware of that already, don't worry haha
At most you could use normal show rules with an #align or smth
bruh, not the "normal show rules". they are the plague that makes the document fall apart really quickly with heavy customizations.
there is also breakable stuff, that might get affected.
I'm just sayin' pal
That's the best you can do rn
Otherwise there isn't much you can do
me too
Fair
We are engaging in simultaneous human communication
The truth is that we live in a society
we live in a society
align[0m[31m:[0m (x, y) [0m[36m=>[0m [0m[35mif[0m y [0m[36m==[0m [0m[33m0[0m { center } [0m[35melse[0m {
(left [0m[36m+[0m horizon, left, center, center, center).[0m[3m[34mat[0m(x)
}[0m[31m,[0m
Thought I'd share this comment I ran into about table limitations in LaTeX, I think it might be possible in Typst, but not sure about the status with multi-column support:
https://dercuano.github.io/notes/general-purpose-layout-syntax.html#addtoc_14
This combination of things in LaTeX is annoyingly apparently impossible: multiple-column mode; tables spanning multiple pages/columns; groups of rows within said table which should not be broken apart --- oh, and header rows on the said table which repeat after every column/page break.
(more in the link)
Not sure, an example would be nice
Text felt a bit dense, or maybe it was 2 am and I was too tired
๐
But if you mean #columns(2) then that should be possible and work
Groups of rows - that one we don't have yet
now this one is interesting
i have like zero idea how this could happen
๐
Wow, this is the best error ever:
failed to format citation (this is a bug)
But that means that someone already predicted this.
Oh... there is only one place with that:
โฐโ hg 'this is a bug'
crates/typst/src/model/cite.rs
162: .unwrap_or_else(|| bail!(span, "failed to format citation (this is a bug)"))
yeah uh
it only happens when the header is repeated
or footer
i also tested querying a labelled header inside a header or footer and it worked, so introspection isnt broken, at least not fully
something weird happened with citations
no idea how
well ive nailed it down further, only happens on the first page of a repeated header
on the following pages it's ok
I mean itโs uncommon to put labeled or reference things inside the head or footer so maybe thatโs a issue , but I donโt know
it isnt common yeah
but theres definitely something wrong somewhere
probably some very cursed detail i overlooked
When you repeat items across pages is the first one the real McCoy and the rest just visual duplicate or would the reference be repeated?
nah we layout multiple times
admittedly a bit inefficient but im not sure theres another way due to contextual stuf
i also made a few more discoveries
using 1fr rows for the header or footer also fixes it
and auto row makes the footer error on the first page but not on the rest (just like the header)
but fixed-size row for footer makes it not error at all, while header still errors
so. very interesting
So if I was to put a reference in the header <mylabel> that would probably cause problems if it had more than one copy
i also broke the compiler somehow lol
it's loading forever
i typed rows: (1%, 2em)
lol
hmm interesting
I mean itโs suddenly dumping on you. Not cool
ok for some reason rows: (1%, 2em) makes the compiler go insane
lol
actually it has a memory leak and dies
no idea what's that one lol
Iโm assuming non relative sizes donโt cause issue
technically they're all relative
but i assume you mean non-ratio
I am loving these updates. This is so cursed
welcome to debugging hell
๐
i still dont have any idea what this could be
and especially why it only happens at the first page of the table
Time for some more bug reporting
Did we discuss about grid for mat?
#contributors message
I saw the mat added augment. I didn't like it as it is too specific for concrete cases. It seems just a grid.vline or grid.hline.
I think it is just an oversimplified version of those two. I also didn't like it, and AFAIK you can only change stroke for all of them at once.
Found a nice workaround for this until the show set rule is fixed for table headers:
I usually have a wrapper function to style my tables, so I pass in a value for header-rows and do...
let selectors = for i in range(1, header-rows) {(table.cell.where(y: i),)}
show table.cell.where(y: 0).or(..selectors): strong
The for loop builds an array of selectors to pass to the or() method. Would need to wrap the styling function in an if statement to cover the case where you might have no header.
You could instead pass the header in as a named argument and actually work out the number of rows automagically, but find this way works OK for me.
?r
[0m[35m#let[0m header-rows [0m[36m=[0m [0m[33m5[0m
[0m[35m#show[0m: doc [0m[36m=>[0m {
[0m[35mshow[0m: it [0m[36m=>[0m {
[0m[35mlet[0m selectors [0m[36m=[0m [0m[3m[34mrange[0m(header-rows).[0m[3m[34mmap[0m(i [0m[36m=>[0m table.cell.[0m[3m[34mwhere[0m(y: i))
[0m[35mif[0m selectors.[0m[3m[34mlen[0m() [0m[36m==[0m [0m[33m0[0m { [0m[35mreturn[0m it }
[0m[35mshow[0m selector.[0m[3m[34mor[0m([0m[36m..[0mselectors): [0m[3m[34mstrong[0m
it
}
doc
}
[0m[3m[34m#table[0m([0m[36m..[0m([h],) [0m[36m*[0m header-rows, [a])
I found a odd thing
?render
#table(
columns: (3.47em, 7.88em, 5.42em, 13.22em, 5.42em),
rows: (8.05em, 4.06em, 5em, 11.23em),
stroke: 1pt,
table.cell(
box(
width: 3.47em,
height: -2pt + 5em,
inset: 0pt,
clip: true,
align(
center + bottom,
box(inset: 0.2em, [H]),
),
),
x: 0,
y: 2,
colspan: 1,
rowspan: 2,
fill: black,
inset: 2pt,
stroke: 0.5pt + luma(0%),
),
)
The "H" although it is told to be aligned to the bottom kind of floats in the middle.
it might me my fault. cause the height seems weird.
It's aligned with respect to the box which is only as high as the 3rd row
Yes. yes it is. ๐ ๐ :0 ๐
?render
#table(
columns: (3.47em, 7.88em, 5.42em, 13.22em, 5.42em),
rows: (8.05em, 4.06em, 5em, 11.23em),
stroke: 1pt,
table.cell(
align(
center + bottom,
box(
width: 3.47em,
height: -2pt + 5em,
inset: 0pt,
clip: true,
box(inset: 0.2em, [H]),
),
),
x: 0,
y: 2,
colspan: 1,
rowspan: 2,
fill: none,
inset: 2pt,
stroke: 0.5pt + luma(0%),
),
)
https://github.com/typst/typst/issues/4707 I created a feature request for my question in #quick-questions
sadly the grid ends immediately so it doesn't repeat
I think without introspection trickery its difficult
but with introspection it's possible I think
Probably possible, but more effort than I'm willing to put it in right now for just a referee report :p
just gotta nerd snipe someone into doing it for you ^^
I just noticed something else. Is this a bug?
?render ```
#set page(width: auto,height: 2cm)
#table(
columns: 2,
stroke: none,
table.cell(rowspan: 3)[A],[B],[C],[D],table.hline()
)
or, maybe not a bug, but not always desirable
cc @wary knot
whats wrong here?
The hline shouldn't appear on the first page
if i recall correctly it's how it works, the last hline is repeated on every page
the last hline in every table you mean?
yes
using cell stroke instead of hline could even it out in terms of priority
cuz hlines are always top priority
but i dont remember the full semantics for conflict between the repeating stroke and previous strokes, i think a previous stroke wins if it's higher priority, but not if it's <=
FYI, I had a hard time reading this until I formatted the code (too much cramped to a single line). It's better to do that, if you have a chance.
[0m[35m#set[0m [0m[3m[34mpage[0m(width: [0m[35mauto[0m, height: [0m[33m2cm[0m)
[0m[3m[34m#table[0m(
columns: [0m[33m2[0m,
stroke: [0m[35mnone[0m,
table.[0m[3m[34mcell[0m(rowspan: [0m[33m3[0m)[A],
[B],
[C],
[D],
table.[0m[3m[34mhline[0m(),
)
@wary knot okay there's definitely something weird
?r ```
#set page(width: auto,height: 2cm)
#table(
columns: 2,
stroke: none,
table.cell(rowspan: 3)[A],[B],[C],[D],table.hline()
)
?r ```
#set page(width: auto,height: 2cm)
#table(
columns: 2,
stroke: none,
table.cell(rowspan: 3)[A],[B],[C],[D],table.hline(),[E],[F]
)
So this matches what you said about the last hline
looks correct to me
the idea is to allow proper borders around tables
it makes more sense when you include the other lines that repeat too (top, left, right)
w/ that said, we could consider having some way to opt out from this behavior
but it was quite hard to find a good enough API for all use cases :p
it all depends on table stroke vs cell stroke vs v/hline
typst computes priority at each cell border
See the example in https://github.com/typst/typst/issues/4707
I have no strokes, only an hline after the header and between each page
there should be no line at the bottom of the first page in the picture
i cant tell without the code
I know, that's why I wanted to find an mwe
but in principle if theres any stroke at the bottom it will repeat
period
w/ that said, it can be overridden if it's lower priority in previous pages
There's only a stroke on the leftmost cell
are you sure? theres stroke on all cells at the bottom
im not talking about per-cell stroke, but any kind of stroke
including stroke: something in the table
@wary knot okay I finally figured it out. I'm just too sleepy. It was truly just the repeating last hline in the table
But I'd like to disable that behavior
There's no special significance to it in my case
Shouldn't the table.footer be used for what you're talking about?
no, it's for borders
it's similar to blocks with stroke, except that you can control the lines more precisely than just a single line crossing the whole bottom of the table
you can open a feature request for that , we can try to reach some api for this
my point was that there's some special significance to the last line in a table, and to me that sounds like something that should be related to the footer instead
footers are more about repeating cells , this is a separate concept, it's more of a style choice than anything
an issue would be good to collect other people's opinions so we can know which api works best
I understand that tables in Typst don't work well with rotated text, right?
Even if you set reflow: true, it just causes the text to overlap the cell borders and go beyond them.
That sounds like a bug
probably works on main @lone nova
Nope, I'm already on main ๐
?r
#set page(width: 50mm, height: 70mm, margin: 0.5cm)
#set text(size: 10pt);
#table(
columns: 2,
gutter: 5pt,
table.header(
table.cell(colspan: 2, text(size: 1.5em)[*Some name*]),
),
rotate(-90deg, reflow: true, text(size: 1.1em)[Religion]),
rotate(-90deg, reflow: true)[#lorem(15)],
)
Okay so then I don't know, but it's unlikely to be specific to tables. What happens in a rect?
It seems to be table specific.
You have to use ?r separately from your message.
?r
#set page(width: 70mm, height: 70mm, margin: 0.5cm)
#set text(size: 10pt);
#stack(
dir: ltr,
rect(rotate(-90deg, reflow: true)[#lorem(25)]),
rect(height: 50mm, rotate(-90deg, reflow: true)[#lorem(25)])
)
No
?render ```
#set page("a10")
#rect(rotate(33deg, reflow: true,[Religion]))
though I can't reproduce the last example on main
the table I can
@wary knot table shenanigans?
idk what reflow is doing here to be honest, but table does depend on measure() internally, to some extent
it first measures width and then measures with fixed available width to figure out the height
assuming auto columns and rows
I guess they should create an issue
What does setting gutters to auto mean? This is not explained in the doc, and auto for Sizing usually means "fit the element's content", but for gutters there is no content.
As noted in #3959 (comment), auto on {column,row}-gutter does not mean "inherit the value from gutter".
It just the same type as normal sizings. So in this case it is the same as 0pt.
Does this mean auto always resolves to 0pt for grid gutters? Then, wouldn't it be better to use auto on {column,row}-gutter to inherit the value from gutter, and not support auto on gutter?
And what's the point of being able to pass an integer n as a shorthand for n * (auto, ), which, if I understand well, is the same as simply auto, i.e., 0pt?
There isn't really a point. It's really just that both use the TrackSizing type in Rust.
I considered outright removing it during the table rework, but it felt equally pointless to do so
ยฏ_(ใ)_/ยฏ
It may interact a bit weirdly with rowspans, but i remember i at least considered that case
Ok. I'll try to see if I can change that
I think we shouldn't worry too much about it unless there's a nasty bug related to it
It's not great user experience in my opinion, and would let us close #3959 (which is not a bug, but still)
?r
#table(
columns: 2 * (1cm, ),
gutter: auto,
[hey], [ho],
table.cell(colspan: 2)[spaaaaaaaaaanned],
)
I guess this is a case where row-gutter: auto makes sense, but this requires more work than just not allowing auto for gutter
I don't really see the point of having auto on column-gutter inherit from gutter. What would be the use case for that?
I think it makes it easier to understand for the user, for two reasons:
- This is how a user would have to implement a shorthand-like argument in a custom function (without using argument sinks).
- It would improve the documentation (see the aforementioned issue).
Iโm curious whether you think adding a gutter option to table.hline (and to table.vline) is worthwhile; after all, you could always adjust the gutters of the table itself instead
Description In good old booktabs manner, I would love to see a gutter (or the like) option for table.hline(), so table.hline() can introduce an additional vertical space around the line. I'm cu...
conceptually, i think some way to configure a particular gutter around some row would make more sense than attaching it to table lines, cuz in practice theres no relation between gutters and lines
in particular ive had the idea in the back of my mind for a while now of having some sort of table.row or table.rows primitive to configure a row / group of rows on the spot
but at least for me thats gonna be lower priority , there are other table things i want to do first
like i'd love to get the multiple headers idea going at some point
worth clarifying that none of this would come for 0.12 though, just some thoughts for the future
||I can't forward without somehow making an old thread recent... so stupid||
Instead of this:
[0m[35m#show[0m table.cell.[0m[3m[34mwhere[0m(y: [0m[33m0[0m): [0m[3m[34mstrong[0m
[0m[3m[34m#table[0m(
columns: [0m[33m2[0m,
align: (_, y) [0m[36m=>[0m [0m[35mif[0m y [0m[36m==[0m [0m[33m0[0m { center } [0m[35melse[0m { left },
table.[0m[3m[34mheader[0m[ะะผั][ะ ะพะปั],
[0m[36m..[0m.
)
You would simply do this:
[0m[35m#show[0m table.[0m[3m[34mheader[0m: [0m[35mset[0m [0m[3m[34malign[0m(center)
[0m[35m#show[0m table.[0m[3m[34mheader[0m: [0m[35mset[0m [0m[3m[34mtext[0m(weight: [0m[32m"bold"[0m)
[0m[30m// #show table.header: strong[0m
[0m[3m[34m#table[0m(
columns: [0m[33m2[0m,
align: left,
table.[0m[3m[34mheader[0m[ะะผั][ะ ะพะปั],
[0m[36m..[0m.
)
there is nothing blocking it other than https://github.com/typst/typst/issues/3640
until that's fixed it's a no go
okey-dokey
My main concern is will Typst allow this, since, IIUC, the intended way is to use alignment callback in the table constructor.
it wouldnt be too different from #show table.cell: set align(...), which generally doesnt look very good
table.header is never laid out as an element, so show-set doesnt have an effect
as well as just show
This is what I wanted to ask. If you can do that for the table cell show rule, then it makes sense that you can do the same with header.
it's desirable, yes
the reason it doesn't work is that the header's cells are laid out, not the header itself
no, I mean this
does this work
probably not as you'd expect
hm
ideally you'd write #show table.cell: set table.cell(align: ...)
but that's not possible atm (it's a separate issue)
similarly for your header proposal you'd be able to write #show table.header: set table.cell(align: ...)
oh... So both will work in the end? this and previous show-set rule?
Isn't this... too much of ways to do the same thing?
#show table.cell: set table.cell(align: ...) is probably always gonna be preferred
if it's ever supported
Don't say that!
it will, I mean at least some way should be supported
lol
thats not what i meant, i meant unless we change how tables work more fundamentally
the thing is, it's not the same
Table rewrite v2 when
If you look at a bigger picture, then yes.
roughly set align applies to the cell as a whole, including stuff coming from other table.cell properties, while table.cell(align: ...) applies only to its body
thats not 100% accurate but thats more or less the idea
stuff coming from other cell properties?
like align itself and also inset
i wont remember now the exact list but it's in the show rule for cells
I thought of: show cell: set align() will modify the alignment of all blocks inside... This doesn't make sense. I think either way everything inside will inherit the new alignment. So show cell: set cell(align) should would the same in this regard.
yeah it's recursive, so the body is always affected
Explain how setting cell alignment affects/interacts with cell inset. I'm confused.
well i was trying to dig this up but it seems the behavior changed in 0.12
and it was actually writing align(x)[abc] vs table.cell(align: x)[abc]
which is different from the show-set rule
table.cell is basically shown as align(cell.align, pad(..cell.inset, body)) , and the pad would have the effect of "breaking" the alignment inside the body
so align(x)[abc] wouldnt work
but it seems to have changed as of 0.12, particularly this commit https://github.com/typst/typst/commit/34f1a232463bafeb3d8d3fa9adeae33c4bb95b23#diff-96ff5960282cc5e0779470ead3b9065e1d278ce779b66c3c7848fba15c862e1d
so there probably wont be much of a difference now, though there might be some edge case im not aware of
What if Typst could infer the width of a table from the array provided to table.header?
That would be so convenient and make some sense imo; I think tables are really missing an easier way to specify dimensionality without a hard coded number
What exactly do you mean by this, automatically sized based on header width?
Not all tables have a header though, and I don't think it necessarily needs to have the same number of cells as the table
For sure, but as a default if the columns parameter of a table is auto, I think it's pretty sane to set it to the length of the header
It sounds like a pretty good way to get that information from the user 'seamlessly' and it encourages always using table.header (which as its documentation suggests is a good idea regardless)
(of course, only if the table logically has a table)
Reminds me of how for [a, b, c] in iter.array_chunks() works without explicitly setting array_chunks::<3>()
You should make a feature request.
that's just normal type inference; [a, b, c] is a pattern for values of type [_; 3]
I've just added a feature request for the tabulate python package https://github.com/astanin/python-tabulate/issues/358 to add Typst support.
It is a very usefult package and is frequently used with pandas dataframes to get nicely formatted tables. It supports loads of output formats (markdown flavors, html, LaTeX...) and it would be great to have there some Typst support.
By the Typst project definition, "Typst is a new markup-based typesetting system for the sciences. It is designed to be an alternative both to advanced tools like LaTeX and simpler tools like ...
I've just found Pypst, which is a nice package too https://krokotsch.eu/pypst/
Is it currently difficult to make a reactive (to page) table figure caption? For long tables.
I'm guessing show table.cell: set table.cell is one of the rules that currently does not work? Is it supposed to work in the future?
https://forum.typst.app/t/problem-with-applying-the-show-rule/3300/2
@wary knot tabularray adopted my feature request https://github.com/lvjr/tabularray/issues/381
hmm, im pretty sure you sent this before? but yeah , neat
Hm
Maybe the feature request itself, but it was only implemented very recently
Do you think something similar could work for typst?
i think they are different models but yeah , i think something like that is possible
perhaps we could just use labels and show-set
at least this works right now...
?r ```js
#show <red-cell>: set text(red)
#table(
[a],
[#table.cell[ast] <red-cell>]
)
but unfortunately it is limited, since you cant show-set on table cell properties atm, as well as on headers
also you cant label a whole row. i suppose this could be one usecase for table.row
and the fact that you have to use markup mode to attach a label is a bit annoying and even misleading, dare i say, so i guess that's another argument to support labels in code mode
The issue that table input is a bit annoying (for manual tables, but also for data-generated table) because cells jump around if one is missing has come up a couple of times now. But, more generally, in my opinion, creating and styling complex tables is a bit of a hassle currently.
Aside from table.row (and possibly table.column), which were proposed before, I'd also like to throw a table.region function into the ring. This would be a rectangular subregion of a table, with the following characteristics:
- On the region, you can set parameters like stroke etc. just like on the table.
- Within the region, the
xandyparameters of cells are relative to the region. - Within a region, a
table.rowandtable.columnare local to that region. - The region could be used in show/set rules.
The main benefit is that this makes it easy to decouple data cells from "meta" cells instead of having to stitch everything together into a single stream of cells and having complicated styling rules based on x/y.
The idea is quite fresh and untested and I haven't gotten around to experimenting with how well this would work out in practice, but I think it could be quite useful. Typically, it's not random if a table styling differs across parts of a table. It's because for the human reader, the table decomposes into different pieces with different meaning. Making this explicit could make styling quite a bit easier.
Well, Ive been considering adding row groups (that aren't headers or footers) for a while, but i suppose a more general region is useful
In general, have the auto cells automatically avoid some predefined cells without having to manually position them (the predefined cells themselves can be auto)
Though I'm not sure about the positioning, having x / y be relative to the region sounds circular at first as the region in theory would inherit the position of its children, but i suppose thats a less useful behavior compared to manually setting something like top left corner + width and height
So there's some room for flexibility, but I think I'd create separate fields such as dx/dy to ensure x/y in table.cell has only one meaning
In my model, the region would auto place itself like a large cell with colspan/rowspan would. Those I suppose the width/height determination of the region would require some thought to avoid cycles. Perhaps it would just need to be explicitly given. (At least the width)
Also somewhat related to this, there is currently no way of expressing header columns, or just singular header cells (which could be regions I guess).
How does region link with rows and how is it determined how big a region is? I would aim to avoid having to specify explicit column/row counts as much as possible for direct table editing. Let's say I input a region with cells (a, b, c, d)(e, f, g, h) - that's 2 x 4 and I don't need to tell the function the size of the region is 2 x 4, hopefully.
With row oriented editing, table(row[A, B], row[A, B, C]) would be a perfectly fine table and it implicitly has 2 rows and 3 columns, that's how I'm thinking about it. (Taking some syntax shortcuts here, if it's table.row[A][B] or something else is a separate issue)
Note that a region could also contains rows. I think I would add all of region and row and column.
aha. I was also asking because I don't have the context. I'm just trying to gather understanding - is there a model that you're thinking of how this works, maybe from a prior dicussion. For example about implicit vs explicit positions and sizes (row and column count)
Another thing. I'm also making experiments with "setrow/setcol" directives. Also a little bit inspired from tabularray (thought it is a deprecated syntax there).
It looks something like this - inserting directives to color specfic rows:
#show table: setrowrules
#rowtable(
stroke: (x: 1pt, y: 0pt),
[Alpha & Beta & Gamma #setrow(cyan)],
[Epsilon & Zeta & Eta #setrow(aqua)],
[Iota & Kappa & Lambda #setrow(violet.lighten(50%))],
)
On it's own it's a bit meh, but it has a benefit that we again put the row style physically in the row it should affect, sometimes that's good.
It's also meh because in a table.row world this could just be table.row([...], fill: cyan) but there is more.. (Also but: We can't have both table.row and table.column at the same time; but we can easily do insersecting setrow and setcol at the same time)