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

bounding box used by tikzexternalize doesn't include drop shadows #1296

Open
fdedinec opened this issue Nov 29, 2023 · 3 comments
Open

bounding box used by tikzexternalize doesn't include drop shadows #1296

fdedinec opened this issue Nov 29, 2023 · 3 comments
Labels

Comments

@fdedinec
Copy link

Brief outline of the bug

When using drop shadows, Tikzexternalize doesn't seem to include the shadow in the bounding box used to externalize a picture: in the MWE some shadows disappear.
If you uncomment the \tikzexternalize line, you get a different (and correct) figure, so I assume it is a bug (either of shadows, or of tikzexternalize, or of whatever machinery that computes current bounding box).

For potential other victims: a temporary workaround is to manually add an invisible line that extends the current bounding box by the size of the drop shadow. See the MWE, too.

Our use case for tikzexternalize: we wrote a full book with several hundred beautiful tikz figures, and then the publisher demanded separate files for each figures... In this case tikzexternalize takes several hours to run but it saved the day.

Thanks for TikZ at large.

Minimal working example (MWE)

\documentclass{book}

\usepackage{tikz}
\usetikzlibrary{shadows}
\usetikzlibrary{external}
\tikzexternalize % activate!

\tikzset{
  hwblock/.style={draw, rectangle, rounded corners=.3, thick, fill=black!2, drop shadow={shadow xshift=1ex,shadow yshift=-1ex}}
}

\begin{document}

This figure has some of its shadow truncated:

\begin{tikzpicture}
  \draw(0,0) node[hwblock] {Box with shadow};
  \draw(15ex,-5ex) node[hwblock] {Box with shadow};
  \draw(-15ex,-5ex) node[hwblock] {Box with shadow};
\end{tikzpicture}


~\\
It should look like the figure below, obtained using a manual fix:

\begin{tikzpicture}
  \draw(0,0) node[hwblock] {Box with shadow};
  \draw(15ex,-5ex) node[hwblock] {Box with shadow};
  \draw(-15ex,-5ex) node[hwblock] {Box with shadow};
  \draw[opacity=0] (current bounding box.north west) --  (current bounding box.south east) -- ++(1ex,-1ex);
\end{tikzpicture}

\end{document}
@muzimuzhi
Copy link
Member

It's a known limitation of /tikz/general shadow, which is used by /tikz/drop shadow. Thus you do need a manual fix.

From documentation of /tikz/general shadow,

Note that since scaling and shifting is done using canvas transformations, shadows are not taken into account when the picture’s bounding box is computed.

image

Note the example for /tikz/shadow scale already shows this limitation, more or less. The light yellow rectangle on background should be larger if bounding box is auto updated.

Example below uses \useasboundingbox to enlarge bounding box and draws the final bounding box in blue.

% enlarge bounding box by size of shadow shifting
\useasboundingbox ([shift={(1ex, -1ex)}]current bounding box.south east);
Example

\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{external, shadows}
% works with or without externalization
% \tikzexternalenable

\tikzset{
  hwblock/.style={
    draw, rectangle, rounded corners=.3pt, thick, fill=black!2
  },
  hwblock shadowed/.style={
    hwblock,
    drop shadow={shadow xshift=1ex,shadow yshift=-1ex}
  },
  % debug: display the size of bounding box
  every picture/.append style={
    execute at end picture={
      % similar to loading "background" library and setting
      % "show background rectangle, tight background"
      \draw[blue, semithick]
        (current bounding box.north east) rectangle
        (current bounding box.south west);    
    }
  }
}

\setlength{\parindent}{-10pt}
\begin{document}

No shadow\\
\begin{tikzpicture}[nodes={hwblock}]
  \path node                 {Box with shadow}
        node at (15ex,-5ex)  {Box with shadow}
        node at (-15ex,-5ex) {Box with shadow};
\end{tikzpicture}

With shadow, bounding box intact\\
\begin{tikzpicture}[nodes={hwblock shadowed}]
  \path node                 {Box with shadow}
        node at (15ex,-5ex)  {Box with shadow}
        node at (-15ex,-5ex) {Box with shadow};
\end{tikzpicture}

With shadow, bounding box enlarged manually\\
\begin{tikzpicture}[nodes={hwblock shadowed}]
  \path node                 {Box with shadow}
        node at (15ex,-5ex)  {Box with shadow}
        node at (-15ex,-5ex) {Box with shadow};
  % enlarge bounding box by size of shadow shifting
  \useasboundingbox ([shift={(1ex, -1ex)}]current bounding box.south east);
\end{tikzpicture}

\end{document}

image

@muzimuzhi
Copy link
Member

For potential other victims: a temporary workaround is to manually add an invisible line that extends the current bounding box by the size of the drop shadow.

Actually to enlarge bounding box you only need an invisible coordinate, so \path (x,y); works too.

Our use case for tikzexternalize: we wrote a full book with several hundred beautiful tikz figures, and then the publisher demanded separate files for each figures... In this case tikzexternalize takes several hours to run but it saved the day.

If in your real document the scale and shifting of shadow is more dynamic or marking pictures using shadows may take too much effort, I can try to provide an automatic workaround.

@fdedinec
Copy link
Author

fdedinec commented Dec 1, 2023

Thanks for the quick reply.
I already added manually my (uselessly complex, OK) workaround to all the affected figures, so no hurry.

Now I understand that the limitation is stated in the shadows doc (I hadn't found it so far).

However, I still believe that from the point of view of a user of tikzexternalize, it is a bug: the pdf output with externalization is different from the pdf without.
A temporary fix could be a warning in the doc of tikzexternalize :)

Even with the fix, the figures are now slightly larger when we switch off externalization, so the book layout may change.
A better workaround would be protected by a \if_I_am_being_externalized { } \fi
Is this possible?

But if you know how to do it automatically I think it is worth it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Development

No branches or pull requests

2 participants