10000 Multi-column Float Elements (Figures, Tables, Code Blocks, etc.) · Issue #553 · typst/typst · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

Multi-column Float Elements (Figures, Tables, Code Blocks, etc.) #553

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
giannissc opened this issue Apr 3, 2023 · 55 comments · Fixed by #5017
Closed

Multi-column Float Elements (Figures, Tables, Code Blocks, etc.) #553

giannissc opened this issue Apr 3, 2023 · 55 comments · Fixed by #5017
Labels
feature request New feature or request layout Related to layout, positioning, etc.

Comments

@giannissc
Copy link
Contributor
giannissc commented Apr 3, 2023

Supersedes: #137.

I want to be able to break the column rules for figures and tables to the full size of the page and I want to be able to float these elements. I believe these two must be tackled together as you can see in the motivating examples

@laurmaedje laurmaedje added feature request New feature or request layout Related to layout, positioning, etc. labels Apr 3, 2023
@reknih reknih changed the title [Feature Request] Multi-column Figure and Tables Multi-column Figure and Tables Apr 4, 2023
@giannissc

Copy link
Contributor Author
giannissc commented Apr 4, 2023

Currently elements cannot break away from their local scope. If columns is activated globally in the document, subsequent elements cannot break from their column parent to use the full width of the page.

A separate issue is that if an element (e.g. image) doesn't fit into the remaining space it will move to the next page/column leaving a blank space behind it.

These two issues, while separate, must be tackled together as there are complex interactions between them.

To solve the first issue I propose that we introduce a scope argument to all the layout methods. Scope can either be global (relative to page) or local (relative to parent [existing behavior]).

To solve the second issue I propose a new layout element #wrap or #float (no strong preference but for the rest of this post I will be using #wrap). #wrap is the counterpart to #place. Unlike place however, it can participate in the flow.

The function signatures would be:

  • #place(scope, alignment, dx, dy, body)
  • #wrap(scope, [alignment], dx, dy, body)

alignment:

  • No alignment - []:
  • Primary alignment - [alignment]:
  • Primary + Secondary alignments - [alignment, alignment, ...]
  • Secondary alignment - [, alignment, ...]

@giannissc
Copy link
Contributor Author
giannissc commented Apr 4, 2023

Algorithm for #wrap elements:

  1. Calculate #wrap element's dimensions and check if the element can fit to existing page/column (other #wrap elements might already populate the page)
  2. If it can, place #wrap element at correct position in current page/column based on its alignment policy. Relayout all other content (except other #wrap elements) in current page/column.
  3. If not, place #wrap element at correct position in the next page/column based on its alignment policy. Keep adding content to current page until it is filled.

@giannissc
Copy link
Contributor Author
giannissc commented Apr 4, 2023

In case 2 or more #wrap elements are placed in the same position in a page/column fallback arguments can be used to decide its position:

  • Repeated secondary alignment - [alignment1, alignment1]: place it to the next available spot (e.g. if 2 #wrap elements request the top position then place the first #wrap element at the top and the second #wrap below it.)
  • Alternate secondary alignment - [alignment1, alignment2]: Place the 2nd #wrap to the position indicated by alignment2. Assuming there are no more conflicts the content is laid out again in the available space. If there is another conflict move to the next page and repeat (alignment1 -> alignment2). For example if the first #wrap request the top position then the second can request in the fallback the bottom.
  • Only primary alignment - [alignment]: no fallback value is provided, move to the next page and repeat (alignment)
  • No primary alignment - []: no primary alignment value is provided, try to fit #wrap into existing page/column. Otherwise move to the top of next page/column. If there is a conflict move to an empty space below
  • Only secondary alignment - [, alignment]: Try to place to current page/column at current position. If it doesn't fit or there is some other conflict use secondary alignment. If there are more conflicts move to the top of next page and repeat

@giannissc
Copy link
Contributor Author

Does this seem reasonable? @laurmaedje, @reknih

Also is this the best place to discuss or do you prefer discord?

I am also willing to contribute code to get this out sooner! 🙂

@giannissc
Copy link
Contributor Author
giannissc commented Apr 5, 2023

Motivating Examples

No wrap (existing behavior)

Not allowing text to wrap around other elements can result in the following issue:
Screenshot 2023-04-05 at 08-05-05 Test Paper (copy) – Typst

No wrap,break column rules (global scope)

Simple allowing content to break the column rules and layout based on page will also have the same issue:
Screenshot 2023-04-05 at 08-20-18 Test Paper – Typst

Wrap (local scope) - #wrap(scope: local, alignment: []) - Default

Screenshot 2023-04-05 at 08-08-54 Test Paper (copy) – Typst

Wrap (global scope) - #wrap(scope: global, alignment: [])

Screenshot 2023-04-05 at 08-22-12 Test Paper – Typst

Wrap (global scope) + Alignment(Centered) - #wrap(scope: global, alignment: [center+horizon])

Screenshot 2023-04-05 at 08-34-00 Test Paper – Typst

Wrap (global scope) + Conflict (Repeated) - #wrap(scope: global, alignment: [top, top])

Screenshot 2023-04-05 at 08-35-25 Test Paper – Typst

Wrap (global scope) + Conflict (Alternate) - #wrap(scope: global, alignment: [top, bottom])

Screenshot 2023-04-05 at 08-37-54 Test Paper – Typst

@giannissc giannissc changed the title Multi-column Figure and Tables Multi-column Float Elements (Figures, Tables, Code Blocks, etc.) Apr 5, 2023
@Andonome
Copy link
Andonome commented Apr 5, 2023

This is great. In fact, it'd be ideal.

@giannissc
Copy link
Contributor Author

Do you think the primary and secondary alignments are both necessary? @Andonome

@eltos
Copy link
Contributor
eltos commented Apr 5, 2023

This is the most important missing feature to make typst as powerful as LaTeX.

@Andonome
Copy link
Andonome commented Apr 5, 2023

Do you think the primary and secondary alignments are both necessary? @Andonome

I wouldn't say 'necessary', but I've found a great deal of flexibility in having both 'top' and 'bottom' options.

This page looks fine, as-is, but the two elements float apart when more text is added, which matches the general format of pictures-at-bottom, and tables-on-top.

image

I've not found tables in the centre work very often.

Of course if anyone wants to get really fancy, automatic wrapping around a PNGs filled parts would be punk-as-all-heck.

@Andonome
Copy link
Andonome commented Apr 5, 2023

This is the most important missing feature to make typst as powerful as LaTeX.

LaTeX doesn't have this ability. There is no reliable text wrapping in a multicols environment. It's a big factor which stops it having reliable output - every compile, every page needs to be checked, images moved, et c.


Edit: I see I've received some silent naysayers downvoting this comment.

If anyone wants to put their code where their mouth is, check out my main project, and get any 3 images (of your choosing) to float, using any macro you please.

@giannissc
Copy link
Contributor Author

@Andonome I think is wrap is to be implemented it should be implemented with all these usecases in mind. Another usecase that comes to mind is that you have a central circular figure and that text should wrap around it as well. You examples are genuinely useful. Thanks!

@giannissc
Copy link
Contributor Author

In you table and figure example would you want to force text to move to the next page or would it be ok for it to render in-between the two elements?

@Andonome
Copy link
Andonome commented Apr 6, 2023

@Andonome I think is wrap is to be implemented it should be implemented with all these usecases in mind. Another usecase that comes to mind is that you have a central circular figure and that text should wrap around it as well. You examples are genuinely useful. Thanks!

Would a showcase be useful? I've had a bunch of ugly results with difficult elements.

In you table and figure example would you want to force text to move to the next page or would it be ok for it to render in-between the two elements?

It depends on the results. Either could be fine, but what's sorely lacking is the ability to return to the last page for a do-over. LaTeX can't correct previous pages, so you can get these ugly dangling single-lines of text.

I've given headers a bunch of \needspace{ commands to stop them going at the end of a page, but that's left this dangling, when the next couple of \paragraph statements (with Journeys) could have fit between these two images fine.

Of course here it's blocked by the General Tempo Chart, so that should have been moved to after the next paragraph.

image

In a lot of cases, it's far more important to say 'place this element somewhere before the next subsection' than making a statement about the position.

Here's another table that could have been better placed by floating anywhere else after the \subsection{Encounters}.

image

I don't know if there's a non-intensive way to have typst go through a bunch of options involving multiple pages, but maybe there could be a second processing option where the user understands it'll take extra time to process, but the results will make sense. Atm a full LaTeX process can take 20 minutes - that's quite doable for big pushes, but less okay when the results need fiddled with before publishing a new version.

@giannissc
Copy link
Contributor Author
giannissc commented Apr 6, 2023

I have update the proposal based on your previous comments and from conversations in Discord. Here is the updated proposal if you want to have a look @Andonome :

Multi-column Float Proposal.pdf

I haven't thought thoroughly about your latest comment just yet but do you think that the proposal here covers those usecases

@giannissc
Copy link
Contributor Author

Ok I just had another look and your usecase in incredibly useful! I might need to tweak the scope argument with other options such as 8000 paragraph, section, etc. for more fine-grained control!

@giannissc
Copy link
Contributor Author

It depends on the results. Either could be fine, but what's sorely lacking is the ability to return to the last page for a do-over. LaTeX can't correct previous pages, so you can get these ugly dangling single-lines of text.

I am not sure I fully understand this point. Is this something that the algorithm is lacking or is it something that the existing Latex API cannot express. If it is the latter I will make a note on the algorithm implementation portion of the proposal otherwise I will make a note on the motivation and API section as an additional user intent

@giannissc
Copy link
Contributor Author

Proposal v3:
Multi-column Float Proposal-3.pdf

@giannissc
Copy link
Contributor Author

Proposal v4:
Multi-column Float Proposal-4.pdf

@Andonome
Copy link
Andonome commented Apr 6, 2023

Proposal v4: Multi-column Float Proposal-4.pdf

This all looks fantastic.

In 1.6:

Giving an option to
disable horizontal wrapping would alleviate the issue.

It might be better to disable this by default. Nobody wants to see 2-words crawling down the side of a table. The table should be centred automatically.

In fact in general, the default being 'typst chooses' is always good. Take for example the first example table. It's clearly best presented image-wide, but that won't always be obvious until the page has processed. If the floating default behaviour was for typst to choose how it floats (and only request the user states if it should be in the same section or page as something else) then it'd really help in producing unattended document production.

@0x7CFE
Copy link
0x7CFE commented Apr 21, 2023

I can suggest reading the Lillypond essay about problems of automated music engraving. I believe, a lot of ideas are common to any complex layout system and potentially can be applied to typst as well.

tldr: Music notation is much more complicated than one can imagine. Naive approach to notation layout based on the hierarchy of containers (page→staff→lines→notes etc) simply does not work. Once in a while you will face some quirky notation like multi-staff slurs or beams, and things will get complicated. In the end, this will result in a lot of ad-hoc code, or the result will not be visually pleasing. Lillypond uses completely different approach to layout.

@granthamtaylor
Copy link

I just wanted to add my +1 here.

I'm trying to write up a whitepaper in IEEE format and floating tables / figures are not possible AFAIK.

@KronosTheLate
Copy link
Contributor

It would be lovely to see this feature implemented.

@denkspuren
Copy link
Contributor

I'm impressed by your solution Nathan! Great work!

@davidleejy
Copy link

A solution in the meantime: https://github.com/ntjess/wrap-it PR is here: typst/packages#357

It handles the common cases (think of it like a less-finicky version of wrapfig), but there are still some fundamental limitations that can't be solved in typst

This looks pretty neat. Does anyone know whether it's possible to position a table spanning the width o A93C f the page in typical Typst 2-column layout with this package?

@danaugrs
Copy link
danaugrs commented Apr 6, 2024

A solution in the meantime: https://github.com/ntjess/wrap-it PR is here: typst/packages#357
It handles the common cases (think of it like a less-finicky version of wrapfig), but there are still some fundamental limitations that can't be solved in typst

This looks pretty neat. Does anyone know whether it's possible to position a table spanning the width of the page in typical Typst 2-column layout with this package?

Doesn't seem like it's possible - at least I wasn't able to. Maybe @ntjess knows a workaround?

@RaulDurand
Copy link

Im not sure if it was already discussed elsewhere but I believe that the ability to place multicolumn floats should be a feature of columns (reflowing the text as needed) instead of a temporary break of the columns element.

@a-stevan
Copy link

i encountered the same issue whilst using the charged-iee template, i wasn't able to put a figure containing a large / wide image at the top, spanning the two columns 🤔

having this feature or a workaround would be really great 😇

@vivek2000anand
Copy link

Any idea when this feature will be added?

Copy link
Member

@Vivdaddy We plan to take a closer look at this for 0.12, but I can't make any promises.

@danaugrs
Copy link
danaugrs commented Jul 17, 2024

It seems like spanning a figure across all columns should be relatively straightforward to implement and it would fix 90% of all multi-column issues. Specially if the figure is at the top or bottom of a page. It would be as if a page with such a figure were a little shorter and the page break happened a bit before or after the actual page break in order to make space for the figure. I know that if this feature were implemented it would prevent me from temporarily switching back to LaTeX, and it seems a lot of people are also anxiously waiting for this (over 100 users if we go by GitHub reactions, but I suspect there are many more). Please let us know when you have updates! ❤️

@Enivex
Copy link
Collaborator
Enivex commented Jul 17, 2024

It seems like spanning a figure across all columns should be relatively straightforward to implement and it would fix 90% of all multi-column issues. Specially if the figure is at the top or bottom of a page. It would be as if a page with such a figure were a little shorter and the page break happened a bit before or after the actual page break in order to make space for the figure. I know that if this feature were implemented it would prevent me from temporarily switching back to LaTeX, and it seems a lot of people are also anxiously waiting for this (over 100 users if we go by GitHub reactions, but I suspect there are many more). Please let us know when you have updates! ❤️

I suspect that if it was straightforward the issue wouldn't still be open.

@danaugrs
Copy link

I suspect that if it was straightforward the issue wouldn't still be open.

This issue is about arbitrary multi-column float elements, which is a complex problem, specially if it involves arbitrary-shape text wrapping as in the last image in this comment. My objective was to point out that there is a subset of this problem space i.e. spanning an element across all columns of a page, specially at the top or bottom of a page (with no arbitrary-shape text wrapping), which is simpler to implement, and would solve the majority of use cases. I think any attempt at a solution should first focus on this.

@andrewboldi
Copy link
andrewboldi commented Jul 19, 2024

@laurmaedje Any progress on this feature request? :)

@RaulDurand
Copy link
RaulDurand commented Jul 19, 2024

I believe that the lack of support for multi-column figures and tables is the main limitation to using Typst for writing manuscripts for scientific journals.

@kescobo
Copy link
kescobo commented Jul 19, 2024

is the main limitation

It depends on the field - almost nothing I submit to (in biology) uses multi-column layouts, but I need line numbers (happily that's being worked on #352 )

@DKierner
Copy link
DKierner commented Jul 20, 2024

I believe that the lack of support for multi-column figures and tables is the main limitation to using Typst for writing manuscripts for scientific journals.

Definitely true for informatics and computer sciences where the IEEE format is quite common. Some stuff is just to large to fit in a single half-page column meaningfullly.

@danaugrs
Copy link
danaugrs commented Jul 21, 2024

I think the ideal solution, from a user's perspective, would involve adding a single parameter, tentatively called colspan, to non-breakable block elements, which would specify how many columns that element should span. Specifying a colspan of more columns than exist in the current context would result in an error. I think such a parameter, coupled with the existing usage of placement: "auto" | "top" | "bottom", would provide complete freedom to place multi-column blocks anywhere as desired.

@jounathaen
Copy link

I'm not a mod, but I think that there are now enough "This feature is stopping me from using Typst"/"This feature is missing for XYZ support" comments in this issue. The Devs are aware of this issue, and it is as-of-now the third most upvoted issue. So instead of adding more comments of the same, I'd suggest using the emoticons to express your support for this feature.
(And the selfish remark: Then people that have subscribed to this issue will not get spammed with non-progress messages)

@NeutrinoLiu
Copy link
NeutrinoLiu commented Aug 29, 2024
Screenshot 2024-08-29 at 12 58 01 AM

in case anyone who is still waiting for the new feature, here is my bypass (i really like typst and would never go back to latex, so i have played with the problem for quite a while):
add your figure to the first column and wrap it with a place function, so that it appears in the middle of two cols. Then at the top of second column, you place another empty rect, so that contents on the right side will align with left side.

#place(
 top,
 dx: 105%,
 float: true,
 clearance: 0pt,
 figure(
   place(
     auto,
     dx: -40%,
     float: true,
     clearance: -8pt,
     figure(
       table(
         align: center,
         columns: (80pt, 80pt, 80pt, 80pt, 80pt),
         [Primitive], [Rendering Quality], [Rendering Speed], [Accessibility], [Storage],
         [3DGS @3dgs], [high], [high (>100fps)], [relatively easy], [middle],
         [NeRF @nerf], [high], [low (\<10fps)], [relatively easy], [low],
         [point cloud], [depends], [middle], [easy], [high],
         [mesh], [depends], [high], [poor], [middle]
       )
     ),
   ),
   caption: [Comparison between different 3D representation]
 ),
)
#lorem(500)
#place(
 top,
 float: true,
 rect(height: 87pt, fill: none, stroke: none)
)

you might want to adjust the location of the second place and the rect height so that visually it looks like that the table spans two columns. a nested place is used here to shift caption and table by different percentage. Interesting thing that the figure could still recognize the place wrapped table and generate "Table 1" as caption correctly.


i did not find a way to append a label in this case, so i simply type in "Table 1" whenever i refer it.

@spped2000
Copy link
spped2000 commented Sep 19, 2024
#place(
  top,
  dx: 70%, 
  float: true, 
  clearance: 0pt,
  figure(
    place(
      auto,
      dx: 0%, 
      float: true, 
      clearance: 0pt,
      image("A2.png", width: 200%)
    ),
    caption: [Visualization of Zero-Shot, Few-Shot model.] // Centered under the image
  ),
)
#place(
  top,
  float: true,
  rect(height: 5pt, fill: none, stroke: none)
)
#lorem(500)
#place(
  top,
  float: true,
  rect(height: 290pt, fill: none, stroke: none)
)

Screenshot 2024-09-19 103051

@a-stevan
Copy link

@NeutrinoLiu and @spped2000 👋

so i've tried your examples and they did not work on my side...
could you share a complete repro of your examples? that would be amazing

my repro

i have installed Typst today with

cargo +1.77 install --git https://github.com/typst/typst --locked typst-cli

and i get the following typst --version

typst 0.11.0 (8c813cb7)

my Typst source is a single file, called main.typ and which contains

#show: rest => columns(2, rest)

#place(
 top,
 dx: 105%,
 float: true,
 clearance: 0pt,
 figure(
   place(
     auto,
     dx: -40%,
     float: true,
     clearance: -8pt,
     figure(
       table(
         align: center,
         columns: (80pt, 80pt, 80pt, 80pt, 80pt),
         [Primitive], [Rendering Quality], [Rendering Speed], [Accessibility], [Storage],
         [3DGS 3dgs], [high], [high (>100fps)], [relatively easy], [middle],
         [NeRF nerf], [high], [low (\<10fps)], [relatively easy], [low],
         [point cloud], [depends], [middle], [easy], [high],
         [mesh], [depends], [high], [poor], [middle]
       )
     ),
   ),
   caption: [Comparison between different 3D representation]
 ),
)
#lorem(500)
#place(
 top,
 float: true,
 rect(height: 87pt, fill: none, stroke: none)
)

then i compile this with

typst compile main.typ main.pdf

and here is what i get 😕
Screenshot from 2024-09-23 14-09-50

@laurmaedje
Copy link
Member

Good news: #5017

@sschuldenzucker
Copy link

Hey guys, I'm probably missing something but can I use the new layout engine to wrap text around figures? The wrap-it package says that it's only relevant as long as this issue isn't resolved. Since it is now, does this mean I can actually wrap text around figures? (and how?) Or is it still not possible and the package documentation should be updated?

@laurmaedje
Copy link
Member

@sschuldenzucker Text wrapping around figures at the side was not part of the 0.12 work on floating placement. This subfeature was also proposed in this issue, but it was too large of an issue to be actionable. Side-wrapping is now tracked by #5181.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature request New feature or request layout Related to layout, positioning, etc.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

0