Skip to content
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

Improve tikz library #29

Open
projetmbc opened this issue Jul 2, 2021 · 28 comments
Open

Improve tikz library #29

projetmbc opened this issue Jul 2, 2021 · 28 comments
Labels
feature request New feature or request
Milestone

Comments

@projetmbc
Copy link

projetmbc commented Jul 2, 2021

nicematrix use of names of the cells to play with TikZ for (even if this fine-tunings is used in some rare situations).

This could be a feature proposed only when using \UseTblrLibrary{tikz}.

@lvjr lvjr added the future plan 🚀 Something for the future label Jul 2, 2021
@lvjr
Copy link
Owner

lvjr commented Jul 2, 2021

Tabularray doesn't have this feature at this moment. Maybe in the future. Seems it need some hooks too (see also #27).

@lvjr
Copy link
Owner

lvjr commented Jan 14, 2023

In fact, nicematrix could create three nodes for each cell; the names of them are of the type i-j, i-j-medium and i-j-large. I am inclined to create only one node for each cell in tabularray.

Moreover, nicematrix creates a coordinate node i at each intersection of the ith hline and ith vline, hence coordinate i-|j is at the intersection of the ith hline and jth vline. (What if the number of rows is not equal to the number of columns? I haven't checked the code yet.)

First of all, we need to decide whether or not tabularray will adopt all the above interfaces of nicematrix.

@lvjr lvjr changed the title Suggestion - TikZ naming of cells Suggestion - TikZ naming of cells and borders Jan 14, 2023
@lvjr
Copy link
Owner

lvjr commented Jan 14, 2023

Also, nicematrix loads pgfcore but not tikz. Maybe tabularray could do the same and call it pgf library but not tikz library.

@lvjr lvjr added feature request New feature or request and removed future plan 🚀 Something for the future labels Dec 18, 2024
@lvjr lvjr changed the title Suggestion - TikZ naming of cells and borders Improve tikz library Dec 18, 2024
@lvjr
Copy link
Owner

lvjr commented Dec 18, 2024

I have merged pull request #554 (Add tikz library) contributed by Jasper Habicht. We can discuss further improvements to this library in this issue.

@jasperhabicht
Copy link
Contributor

jasperhabicht commented Dec 18, 2024

I just read issue #27 about PDF tagging and I think it might be a good idea to add another hook directly before tabularray/cell/after where the TikZ node is inserted to make sure the TikZ node (which should be handled as artifact in terms of tagging) is not being placed outside the cell.

@lvjr
Copy link
Owner

lvjr commented Dec 18, 2024

As far as I know, by default contents not tagged as mcs by some code are treated as artifects by tagpdf. So tblrlibtagpdf needs only to put its hook before tblrlibtikz by using \DeclareHookRule.

@lvjr
Copy link
Owner

lvjr commented Dec 21, 2024

In above commit I have added tblrtikzbefore and rename tblrtikz as tblrtikzafter. Here is an example:

\documentclass{article}
\usepackage{tabularray}
\UseTblrLibrary{tikz}
\usetikzlibrary{patterns}
\begin{document}
BEFORE%
\begin{tblrtikzbefore}
  \fill[pattern color=lightgray,pattern=bricks]
    (table.north east) rectangle (table.south west);
\end{tblrtikzbefore}%
\begin{tblr}{
    hlines, vlines, 
    colspec={ l l l l },
    hline{1} = {2pt},
    vline{1} = {1}{2pt},
    vline{2} = {2}{-}{1pt},
    hline{Z} = {2pt},
    cell{2}{2} = {r=2, c=2}{c}
}
    1 & 2 & 3 & 5 \\
    4 & foo bar baz & 6 \\
    7 & 8 & 9 & 10 
\end{tblr}%
\begin{tblrtikzafter}
    \draw[green] (1-1.north west) circle[radius=1pt];
    \draw[green] (1-1.north east) circle[radius=1pt];
    \draw[green] (1-1.south west) circle[radius=1pt];
    \draw[green] (1-1.south east) circle[radius=1pt];
    \draw[red] (2-2.north west) circle[radius=1pt];
    \draw[red] (2-2.north east) circle[radius=1pt];
    \draw[red] (2-2.south west) circle[radius=1pt];
    \draw[red] (2-2.south east) circle[radius=1pt];
    \draw[blue] (3-1.north west) circle[radius=1pt];
    \draw[blue] (3-1.north east) circle[radius=1pt];
    \draw[blue] (3-1.south west) circle[radius=1pt];
    \draw[blue] (3-1.south east) circle[radius=1pt];
    \draw[yellow] (table.north west) circle[radius=1pt];
    \draw[yellow] (table.north east) circle[radius=1pt];
    \draw[yellow] (table.south west) circle[radius=1pt];
    \draw[yellow] (table.south east) circle[radius=1pt];
\end{tblrtikzafter}%
AFTER
\par\vspace{1em}
\begin{tblrtikzbefore}
  \fill[color=red]
    (table.north east) rectangle (table.south west);
\end{tblrtikzbefore}%
\begin{tblr}{|l|c|c|r|}
\hline
 Alpha   & Beta  & Gamma  & Delta \\
\hline
 Epsilon & Zeta  & Eta    & Theta \\
\hline
 Iota    & Kappa & Lambda & Mu    \\
\hline
\end{tblr}
\end{document}
image

@lvjr
Copy link
Owner

lvjr commented Dec 21, 2024

@jasperhabicht From above example, it seems tikz table node is a bit larger than the table box. Any idea?

@muzimuzhi
Copy link
Collaborator

muzimuzhi commented Dec 21, 2024

You also need /tikz/outer sep=0pt.

This option adds an additional (invisible) separation space of ⟨dimension⟩ outside the background path. The main effect of this option is that all anchors will move a little “to the outside”.
https://tikz.dev/tikz-shapes#pgf./pgf/outer:sep

\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{calc}

\begin{document}
% default "outer sep"
\begin{tikzpicture}[line width=3pt]
  \node[draw=none, fill=none, inner sep=0pt, text width=3cm, text height=2cm] (a) at (0,0) {};
  \draw[red] (a.north east) rectangle (a.south west);
  \draw (-1.5, 0) -- (1.5, 0);
\end{tikzpicture}

% "outer sep=0pt"
\begin{tikzpicture}[line width=3pt]
  \node[draw=none, fill=none, inner sep=0pt, outer sep=0pt, text width=3cm, text height=2cm] (a) at (0,0) {};
  \draw[red] (a.north east) rectangle (a.south west);
  \draw (-1.5, 0) -- (1.5, 0);
\end{tikzpicture}
\end{document}

image

As a cross reference, see how tcolorbox provides tikz nodes for different parts of a tcolorbox.

Update: I just opened #559 to address this.

@jasperhabicht
Copy link
Contributor

jasperhabicht commented Dec 21, 2024

You also need /tikz/outer sep=0pt.

...

As a cross reference, see how tcolorbox provides tikz nodes for different parts of a tcolorbox.

...

True, I missed that. Thanks!

Interesting that the tcolorbox package uses minimum width and minimum height in combination with line height. Having again read the TikZ manual, I think in the case of cells and tables, text width is better, because it will set a fixed width of the node, no matter what its contents are.

Of course, if the node is empty (which it is supposed to be anyways), the result will be the same. But we also need to take into account depth here, so using the text ... options feels more appropriate.

@lvjr
Copy link
Owner

lvjr commented Dec 21, 2024

It seems there is a bug with multispan cells and omitted cells. Here is an example for showing the problem:

\documentclass{article}
\usepackage{tabularray}
\UseTblrLibrary{tikz}
\usetikzlibrary{patterns}
\begin{document}

\section{Normal cells}

\begin{tblr}{|c|c|c|[2pt]|c|c|}
\hline
 \SetCell[r=2]{c} 2 Rows
     & \SetCell[c=2]{c} 2 Columns
           &     & \SetCell[r=2,c=2]{c} 2 Rows 2 Columns & \\
\hline
     & 2-2 & 2-3 &     &     \\
\hline\hline[1pt]
 3-1 & 3-2 & 3-3 & 3-4 & 3-5 \\
\cline[2pt]{1-2}\cline[1pt]{3}\cline[3pt]{4-5}
\end{tblr}%

\section{Multispan cells}

\begin{tblr}{|c|c|c|[2pt]|c|c|}
\hline
 \SetCell[r=2]{c} 2 Rows
     & \SetCell[c=2]{c} 2 Columns
           &     & \SetCell[r=2,c=2]{c} 2 Rows 2 Columns & \\
\hline
     & 2-2 & 2-3 &     &     \\
\hline\hline[1pt]
 3-1 & 3-2 & 3-3 & 3-4 & 3-5 \\
\cline[2pt]{1-2}\cline[1pt]{3}\cline[3pt]{4-5}
\end{tblr}%
\begin{tblrtikzafter}
  \fill[blue7] (1-4.north west) rectangle (1-4.south east);
\end{tblrtikzafter}

\section{Omitted cells}

\begin{tblr}{|c|c|c|[2pt]|c|c|}
\hline
 \SetCell[r=2]{c} 2 Rows
     & \SetCell[c=2]{c} 2 Columns
           &     & \SetCell[r=2,c=2]{c} 2 Rows 2 Columns & \\
\hline
     & 2-2 & 2-3 &     &     \\
\hline\hline[1pt]
 3-1 & 3-2 & 3-3 & 3-4 & 3-5 \\
\cline[2pt]{1-2}\cline[1pt]{3}\cline[3pt]{4-5}
\end{tblr}%
\begin{tblrtikzafter}
  \fill[red7] (1-3.north west) rectangle (1-3.south east);
  \fill[yellow7] (2-1.north west) rectangle (2-1.south east);
  \fill[teal7] (1-5.north west) rectangle (1-5.south east);
  \fill[brown7] (2-4.north west) rectangle (2-4.south east);
  \fill[purple7] (2-5.north west) rectangle (2-5.south east);
\end{tblrtikzafter}

\end{document}
image

lvjr added a commit that referenced this issue Dec 21, 2024
@jasperhabicht
Copy link
Contributor

jasperhabicht commented Dec 21, 2024

The issue with multispan cells is that the anchor cell/after sits where the cell would end if it was a single-column cell. Therefore I needed to shift the node to the right using the width of all covered columns (using \l__tblr_cell_hanchor_dim). Obviously, I messed up this calculation.

As for omitted cells: As long as the hooks are set for the relevant cells, the node is placed. This is not a bug in the library, I think.

@lvjr
Copy link
Owner

lvjr commented Dec 21, 2024

As for omitted cells: As long as the hooks are set for the relevant cells, the node is placed. This is not a bug in the library, I think.

Yes, it is nice that every omitted cell also has a cell node. I think it would be perfect if we can make the cell node zero-width/zero-height if a cell is covered by another multicolumn/multirow cell. But I guess users will not use them, so it is OK to leave them as they are.

@jasperhabicht
Copy link
Contributor

jasperhabicht commented Dec 21, 2024

I added a PR that should fix the issue with multispan cells.

@jasperhabicht
Copy link
Contributor

By the way: with outer sep set to zero, the cell nodes are now exactly the size of the cells which is nice, but it is now not straight-forward to place things exactly on the borders (which was one of the initial requests).

Maybe we should add coordinates at the intersections of the borders ... but we need to think about what to do if borders of different width or multiple borders intersect.

We should gather more use cases before taking action here, I think.

@lvjr
Copy link
Owner

lvjr commented Dec 21, 2024

For a m times n table, it is easy to calculate all coordinates of corners since we have

the y coordinate of corner-1-1 = (table.north west.y + cell-1-1.north west.y) / 2
the y coordinate of corner-2-1 = (cell-1-1.south east.y + cell-2-1.north west.y) / 2
...
the y coordinate of corner-(m+1)-1 = (cell-m-1.south east.y + table.south east.y) / 2
the x coordinate of corner-1-1 = (table.north west.x + cell-1-1.north west.x) / 2
the x coordinate of corner-1-2 = (cell-1-1.south east.x + cell-1-2.north west.x) / 2
...
the x coordinate of corner-1-(n+1) = (cell-1-n.south east.x + table.south east.x) / 2

Therefore we can create these m+n+1 coordinate nodes for corners in tikz library.

And from corner-i-1 and corner-1-j users can use corner-i-j directly with tikz intersection syntax

corner-i-j = corner-i-1 -| corner-1-j

Therefore we don't need to create other corner nodes, which is the case in nicematrix.

The only problem is, multispan cells will hinder our calculations above.

lvjr added a commit that referenced this issue Dec 22, 2024
lvjr added a commit that referenced this issue Dec 22, 2024
@lvjr lvjr added this to the 2025A milestone Dec 22, 2024
@jasperhabicht
Copy link
Contributor

For a m times n table, it is easy to calculate all coordinates of corners since we have

...

So we don't need to create them, which is the case in nicematrix.

The only problem is, multispan cells will hinder our calculations above.

Exactly. I also thought that we should not add more nodes but instead use the existing ones to create coordinates. It should still be possible, I think, to also do this for multispan cells, since the information about how many cols and rows are spanned is accessible for every cell.

One could even add an option allowing the user so switch on/off these additional coordinates if needed.

@lvjr
Copy link
Owner

lvjr commented Dec 22, 2024

The issue with multispan cells is that the anchor cell/after sits where the cell would end if it was a single-column cell. Therefore I needed to shift the node to the right using the width of all covered columns ...

If we also create a cell-i-j-beforeshift node for every multipsan cell in the first row or column, then it would be easier to create all corner nodes. (We are lucky that the node of an omitted cell is the same as cell-i-j-beforeshift. 😄 )

@lvjr
Copy link
Owner

lvjr commented Dec 23, 2024

I have modified the calculations in #29 (comment) , using only north west and south east coordinates of cell nodes. The north west coordinates are always correct for all cells (including multispan and omitted ones). And the south east coordinates are anchors of cell/after hooks with \l__tblr_row_dp_dim shifts, so I think it would be possible to create some private coordinate nodes there for later use.

@jasperhabicht
Copy link
Contributor

jasperhabicht commented Dec 23, 2024

Added a PR that adds a coordinate at the lower right corner in every cell (not only in multispan cells, but this could be changed easily), which could be useful to add the other coordinates.

I also changed the trim of the box to zero and instead shifted the node and coordinate via TikZ to simplify things a bit.

I am unsure when I will be able to contribute more in the next few weeks though.

@lvjr
Copy link
Owner

lvjr commented Dec 24, 2024

Added a PR that adds a coordinate at the lower right corner in every cell (not only in multispan cells, but this could be changed easily), which could be useful to add the other coordinates.

It is nice that every cell has a similar coordinate node.

I am unsure when I will be able to contribute more in the next few weeks though.

Everyone is busy around new year. Thank you again for your contribution.

@lvjr
Copy link
Owner

lvjr commented Dec 24, 2024

I also changed the trim of the box to zero and instead shifted the node and coordinate via Ti_k_Z to simplify things a bit.

It seems the third tests in library-016.tex fails with PR #566. The background grid now stretches a bit out of the table node at the bottom. I can not figure out the reason. (I am not good at tikz.)

image

@jasperhabicht
Copy link
Contributor

I also changed the trim of the box to zero and instead shifted the node and coordinate via Ti_k_Z to simplify things a bit.

It seems the third tests in library-016.tex fails with PR #566. The background grid now stretches a bit out of the table node at the bottom. I can not figure out the reason. (I am not good at tikz.)

image

Okay, then leave it for now. I will look into it as soon as possible. As for now, we do have a working library with nodes for every cell and the table which is already nice!

@lvjr
Copy link
Owner

lvjr commented Dec 28, 2024

With newly added i-j-single nodes, I have created corner nodes h<i> and v<j> in tikz library.

@lvjr
Copy link
Owner

lvjr commented Dec 28, 2024

Here is an example of corner nodes:

\documentclass{article}
\usepackage{tabularray}
\UseTblrLibrary{tikz}
\begin{document}
\begin{tblr}{
    hlines, vlines,
    colspec={ l l l l },
    hline{1} = {2pt},
    vline{1} = {1}{2pt},
    vline{2} = {2}{-}{1pt},
    hline{Z} = {2pt},
    cell{1}{1} = {r=2}{c},
    cell{1}{3} = {c=3}{c},
    cell{2}{2} = {r=2, c=2}{c}
}
    1 & 2       & 3 &   &   \\
      & foo bar &   & 4 & 5 \\
    6 &         &   & 7 & 8
\end{tblr}%
\begin{tblrtikzafter}
  \draw[color=purple3]
    (h1-|v1) -- (h1-|v2) -- (h2-|v2) -- (h2-|v3) -- (h3-|v3) -- (h3-|v4)
             -- (h4-|v4) -- (h4-|v5) -- (h2-|v5) -- (h2-|v6) -- (h1-|v6);
\end{tblrtikzafter}
\end{document}
image

lvjr added a commit that referenced this issue Dec 29, 2024
lvjr added a commit that referenced this issue Dec 29, 2024
@jasperhabicht
Copy link
Contributor

jasperhabicht commented Jan 9, 2025

Some remarks on the current implementation:

  • Why do we use b+ in tblrtikzbefore, but not in tblrtikzafter? Is there a benefit of using one over the other?
  • I wrongly added a superfluous { } to \coordinate in my PR, now on line 7876:
    at ( 0pt , -\l__tblr_row_dp_dim ) { } ;
  • I am wondering whether we really should make use of \box_set_trim:Nnnnn to shift the tikzpictures or use a shift option on the TikZ environment. At least, we should be consistent. It feels using the shift option (or setting the coordinates directly) is cleaner.
  • I am also wondering whether we really need to use the calc library. But as it is loaded only once, it should not have that much of an effect on compilation time. It is of course easier to define the coordinates using the calc library.

@lvjr
Copy link
Owner

lvjr commented Jan 9, 2025

  • Why do we use +b in tblrtikzbefore, but not in tblrtikzafter? Is there a benefit of using one over the other?

We have to collect the body code of tblrtikzbefore before we define the nodes and execute the body code later. So +b is neccesary for tblrtikzbefore. I think without +b we will get errors of undefined nodes.

@lvjr
Copy link
Owner

lvjr commented Jan 9, 2025

  • I wrongly added a superfluous { } to \coordinate in my PR, now on line 7876:
    at ( 0pt , -\l__tblr_row_dp_dim ) { } ;
  • I am wondering whether we really should make use of \box_set_trim:Nnnnn to shift the tikzpictures or use a shift option on the Ti_k_Z environment. At least, we should be consistent. It feels using the shift option (or setting the coordinates directly) is cleaner.

You can fix them as long as the reggression tests don't fail.

  • I am also wondering whether we really need to use the calc library. But as it is loaded only once, it should not have that much of an effect on compilation time. It is of course easier to define the coordinates using the calc library.

Just replace my code with yours if you can do coordinate calculation without calc library. I use calc because I am not familiar with tikz calculation.

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
Projects
None yet
Development

No branches or pull requests

4 participants