5

I'm trying to include a scaled graph into another picture (yes I need to use nested tikz pictures, but I can't find any better way), and the problem is that the arrow heads are not scaled properly, so the scaled graph looks weird. Any idea to scale properly a graph?

I tried \scalebox{.6}{...} which works great for tikzpicture alone, but in nested tikzpicture, the bounding box used is as if the graph wouldn't have been scaled, which makes the positionning ugly.

Also, I could generate first a pdf and include it, but it's not really practical because I want to use it in a beamer slide and I need to include some \onslide<...> command inside, so it means that I would need to create one tex/pdf for each slide...

Bonus: you get a bonus if the method also allow links to nested tikzpicture with remember options.

MWE:

\documentclass[a4paper]{article}

\usepackage{tikz}

\begin{document}
Not scaled:
\begin{tikzpicture}[
    qubit/.style={draw, circle, color=black, anchor=center,
      fill={rgb,255:red,143;green,146;blue,237},
      inner sep=0pt,minimum width=5mm}
    ]
  \node[qubit] (q1) at (0,0){};
  \draw[red,-stealth] (q1.center) -- (q1.north);
\end{tikzpicture}


Scaled:
\begin{tikzpicture}[scale=.5, every node/.style={scale=.5},
    qubit/.style={draw, circle, color=black, anchor=center,
      fill={rgb,255:red,143;green,146;blue,237},
      inner sep=0pt,minimum width=5mm}
    ]
  \node[qubit] (q1) at (0,0){};
  \draw[red,-stealth] (q1.center) -- (q1.north);
\end{tikzpicture}
\end{document}

enter image description here

-- EDIT -- Here is a MWE with the included nested tikzpicture:

\documentclass{article}

\usepackage{tikz}
\usetikzlibrary{calc,positioning}

\begin{document}
Not scaled:
\begin{tikzpicture}[
  qubit/.style={draw, circle, color=black, anchor=center,
    fill={rgb,255:red,143;green,146;blue,237},
    inner sep=0pt,minimum width=5mm}
  ]
  \node[qubit] (q1) at (0,0){};
  \node[qubit,right=of q1] (q2) {};
  \draw[-] (q1) -- (q2);
  \draw[red,-stealth] (q1.center) -- (q1.north);
\end{tikzpicture}

Scale + transform shape:\\
\begin{tikzpicture}
  \node[circle,draw,fill=green] (A) {A};
  \node[circle,draw,fill=green,right=of A] (B) {B};
  \node[circle,draw,fill=green,above=of A] (C) {C};
  \node[above=of B.center,anchor=south east] (graph) {
    \begin{tikzpicture}[scale=0.5, every node/.style={transform shape},
      qubit/.style={draw, circle, color=black, anchor=center,
        fill={rgb,255:red,143;green,146;blue,237},
        inner sep=0pt,minimum width=5mm}
      ]
      \node[qubit] (q1) at (0,0){};
      \node[qubit,right=of q1] (q2) {};
      \draw[-] (q1) -- (q2);
      \draw[red,-stealth] (q1.center) -- (q1.north);
    \end{tikzpicture}
  };
  \node[fill=green,inner sep=0pt,minimum size=3pt] at (graph.north east) {};
  \node[fill=red,inner sep=0pt,minimum size=3pt] at (graph.north west) {};
  \node[fill=yellow,inner sep=0pt,minimum size=3pt] at (graph.south east) {};
  \node[fill=orange,inner sep=0pt,minimum size=3pt] at (graph.south west) {};
\end{tikzpicture}

transform canvas, good arrow size, bad position:\\
\begin{tikzpicture}
  \node[circle,draw,fill=green] (A) {A};
  \node[circle,draw,fill=green,right=of A] (B) {B};
  \node[circle,draw,fill=green,above=of A] (C) {C};
  \node[above=of B.center,anchor=south east] (graph2) {
    \begin{tikzpicture}[transform canvas={scale=0.5},
      qubit/.style={draw, circle, color=black, anchor=center,
        fill={rgb,255:red,143;green,146;blue,237},
        inner sep=0pt,minimum width=5mm}
      ]
      \node[qubit] (q3) at (0,0){};
      \node[qubit,right=of q3] (q4) {};
      \draw[-] (q3) -- (q4);
      \draw[red,-stealth] (q3.center) -- (q3.north);
    \end{tikzpicture}
  };
  \node[fill=green,inner sep=0pt,minimum size=3pt] at (graph2.north east) {};
  \node[fill=red,inner sep=0pt,minimum size=3pt] at (graph2.north west) {};
  \node[fill=yellow,inner sep=0pt,minimum size=3pt] at (graph2.south east) {};
  \node[fill=orange,inner sep=0pt,minimum size=3pt] at (graph2.south west) {};
\end{tikzpicture}

\end{document}

enter image description here

-- EDIT 2 -- I tried with xsavebox as proposed in comments, and it works pretty well, except that it does not deal with beamer overlay, which is quite a big issue in my case...

\documentclass{beamer}
\usepackage{xsavebox}
\usepackage{tikz}
\usetikzlibrary{calc,positioning}

\begin{document}

\begin{frame}
Not scaled:
\begin{tikzpicture}[
  qubit/.style={draw, circle, color=black, anchor=center,
    fill={rgb,255:red,143;green,146;blue,237},
    inner sep=0pt,minimum width=5mm}
  ]
  \node[qubit] (q1) at (0,0){};
  \node[qubit,right=of q1] (q2) {};
  \draw[-] (q1) -- (q2);
  \draw[red,-stealth] (q1.center) -- (q1.north);
\end{tikzpicture}
\end{frame}

\begin{frame}
Scale + transform shape, good position, bad arrow size:\\
\begin{tikzpicture}
  \node[circle,draw,fill=green] (A) {A};
  \node[circle,draw,fill=green,right=of A] (B) {B};
  \node[circle,draw,fill=green,above=of A] (C) {C};
  \node[above=of B.center,anchor=south east] (graph) {
    \begin{tikzpicture}[scale=0.5, every node/.style={transform shape},
      qubit/.style={draw, circle, color=black, anchor=center,
        fill={rgb,255:red,143;green,146;blue,237},
        inner sep=0pt,minimum width=5mm}
      ]
      \node[qubit] (q1) at (0,0){};
      \node[qubit,right=of q1] (q2) {};
      \draw[-] (q1) -- (q2);
      \draw[red,-stealth] (q1.center) -- (q1.north);
      \node<2>[qubit,above=of q2] (q2bis) {};
    \end{tikzpicture}
  };
  \node[fill=green,inner sep=0pt,minimum size=3pt] at (graph.north east) {};
  \node[fill=red,inner sep=0pt,minimum size=3pt] at (graph.north west) {};
  \node[fill=yellow,inner sep=0pt,minimum size=3pt] at (graph.south east) {};
  \node[fill=orange,inner sep=0pt,minimum size=3pt] at (graph.south west) {};
\end{tikzpicture}
\end{frame}

\begin{frame}
  transform canvas, good arrow size, bad position:\\
  \begin{tikzpicture}
    \node[circle,draw,fill=green] (A) {A};
    \node[circle,draw,fill=green,right=of A] (B) {B};
    \node[circle,draw,fill=green,above=of A] (C) {C};
    \node[above=of B.center,anchor=south east] (graph2) {
      \begin{tikzpicture}[transform canvas={scale=0.5},
        qubit/.style={draw, circle, color=black, anchor=center,
          fill={rgb,255:red,143;green,146;blue,237},
          inner sep=0pt,minimum width=5mm}
        ]
        \node[qubit] (q3) at (0,0){};
        \node[qubit,right=of q3] (q4) {};
        \draw[-] (q3) -- (q4);
        \draw[red,-stealth] (q3.center) -- (q3.north);
        \node<2>[qubit,above=of q4] (q5) {};
      \end{tikzpicture}
    };
    \node[fill=green,inner sep=0pt,minimum size=3pt] at (graph2.north east) {};
    \node[fill=red,inner sep=0pt,minimum size=3pt] at (graph2.north west) {};
    \node[fill=yellow,inner sep=0pt,minimum size=3pt] at (graph2.south east) {};
    \node[fill=orange,inner sep=0pt,minimum size=3pt] at (graph2.south west) {};
  \end{tikzpicture}
\end{frame}


\begin{xlrbox}{mybox}
  \begin{tikzpicture}[
    qubit/.style={draw, circle, color=black, anchor=center,
      fill={rgb,255:red,143;green,146;blue,237},
      inner sep=0pt,minimum width=5mm}
    ]
    \node[qubit] (q3) at (0,0){};
    \node[qubit,right=of q3] (q4) {};
    \draw[-] (q3) -- (q4);
    \draw[red,-stealth] (q3.center) -- (q3.north);
    \node<2>[qubit,above=of q4] (q5) {};
  \end{tikzpicture}
\end{xlrbox}

\begin{frame}
xlrbox, good resize, no beamer overlay:\\
\begin{tikzpicture}
  \node[circle,draw,fill=green] (A) {A};
  \node[circle,draw,fill=green,right=of A] (B) {B};
  \node[circle,draw,fill=green,above=of A] (C) {C};
  \node[above=of B.center,anchor=south east] (graph2) {\scalebox{0.5}{\themybox}};
  \node[fill=green,inner sep=0pt,minimum size=3pt] at (graph2.north east) {};
  \node[fill=red,inner sep=0pt,minimum size=3pt] at (graph2.north west) {};
  \node[fill=yellow,inner sep=0pt,minimum size=3pt] at (graph2.south east) {};
  \node[fill=orange,inner sep=0pt,minimum size=3pt] at (graph2.south west) {};
\end{tikzpicture}
\end{frame}

\end{document}
tobiasBora
  • 8,684
  • 2
  • 1
    Not to advertise one of my own questions, but you might find what is the best way to combine tikzpictures and beamer overlays interesting for your application. The proposed answer allows to create 1 pdf document that handles overlays. You could create every specific symbol in a standalone image then include it with overlay specifications ... – BambOo Aug 13 '18 at 12:51
  • 2
    @RuixiZhang The only two methods that really scale correctly are resizebox and transform canvas={scale=0.5}. All the other ones (scale=0.5, every node/.style={transform shape}, scale=.5, every node/.style={scale=.5}...) fails to resize line width and arrow width correctly. The problem of resizebox and transform canvas={scale=0.5} is that they break the bounding box : resizebox does not scale the bounding box, and transform canvas sets the bounding box to the empty box, so the positionning gets ugly when I include the graph in a nested tikzpicture... I'll try to create MWE with nested – tobiasBora Aug 13 '18 at 13:05
  • @BambOo : this question is really interesting, and for now it's the best solution I have so far (and it also solve the problem of compilation time). The only issue is that I need to create one file for each nested picture, and that I can't refer to nodes inside the nested tikzpicture with remember option. – tobiasBora Aug 13 '18 at 14:00
  • 2
    Why didn't anyone comment so far that one should not nest tikzpictures? –  Aug 13 '18 at 16:37

2 Answers2

6

With the xsavebox package you can save the tikzpicture in a xlrbox, and scale it when using:

\documentclass[a4paper]{article}

\usepackage{tikz}
\usepackage{xsavebox}

\begin{xlrbox}{mybox}
\begin{tikzpicture}[
    qubit/.style={draw, circle, color=black, anchor=center,
      fill={rgb,255:red,143;green,146;blue,237},
      inner sep=0pt,minimum width=5mm}
    ]
  \node[qubit] (q1) at (0,0){};
  \draw[red,-stealth] (q1.center) -- (q1.north);
\end{tikzpicture}%
\end{xlrbox}

\begin{document}
Not scaled: \themybox

Scaled: \scalebox{0.5}{\themybox}
\end{document}

This also solves the nesting of tikzpictures.

enter image description here

EDIT (by marmot who is happy to take the blame for all errors;-): You should never nest tikzpictures. You can work with scopes, which you can assign name with the local bounding box trick, these scopes will then behave pretty much like nodes (as far as the remembering and placing stuff relative to them is concerned). Clearly, inside the scope you can work with all overlays in the usual way. The perhaps easiest way to go is to load the arrows.meta library and downscale the arrow. (\pgflowlevelsynccm does not work here in a straightforward way because of the additional translations, otherwise it scales the arrow automatically to the right size, but this command should anyway be used with great care.)

\documentclass{beamer}
\usepackage{tikz}
\usetikzlibrary{calc,positioning,arrows.meta}

\begin{document}


\begin{frame}
Scale + transform shape, good position, bad arrow size:\\
\begin{tikzpicture}
  \node[circle,draw,fill=green] (A) {A};
  \node[circle,draw,fill=green,right=of A] (B) {B};
  \node[circle,draw,fill=green,above=of A] (C) {C};
  \coordinate[above=of B.center] (X);

    \begin{scope}[shift={($(X)+(-1,0)$)},
    transform shape,scale=0.5, 
      qubit/.style={draw, circle, color=black, anchor=center,
        fill={rgb,255:red,143;green,146;blue,237},
        inner sep=0pt,minimum width=5mm},local bounding box=graph]
      \node[qubit] (q1) at (0,0){};
      \node[qubit,right=of q1] (q2) {};
      \draw[-] (q1) -- (q2);
      \node<2>[qubit,above=of q2] (q2bis) {};
      \draw[red,-{Stealth[scale=0.5]}] (q1.center) -- (q1.north);
    \end{scope}
    % comparison
    \draw[red,-stealth] ([xshift=2mm,yshift=-1cm]q1.center) -- ([xshift=2mm]q1.north);
  \node[fill=green,inner sep=0pt,minimum size=3pt] at (graph.north east) {};
  \node[fill=red,inner sep=0pt,minimum size=3pt] at (graph.north west) {};
  \node[fill=yellow,inner sep=0pt,minimum size=3pt] at (graph.south east) {};
  \node[fill=orange,inner sep=0pt,minimum size=3pt] at (graph.south west) {};
\end{tikzpicture}
\end{frame}

\end{document}
Max
  • 9,733
  • 3
  • 28
  • 35
  • Thank you for the trick, which is a great solution in "fixed" pictures (so you get a +1), but as far as I know it does not handle beamer overlays, which is a big issue in my case. – tobiasBora Aug 13 '18 at 13:57
  • @tobiasBora What exactly does/doesn't it do that you would expect otherwise? – Max Aug 13 '18 at 14:01
  • I uploaded a MWE that shows that this solution cannot use beamer overlays like \node<2>[qubit,above=of q4] (q5) {};, or \only<2>{...}. – tobiasBora Aug 13 '18 at 14:03
  • 1
    @tobiasBora Ah so you want nested tikzpictures to comply to beamer overlays. That's a different story entirely. – Max Aug 13 '18 at 14:06
  • 1
    @Max I added something with a scope and local bounding box, please feel free to roll that back. –  Aug 13 '18 at 17:24
  • @marmot The problem of scopes is that, as far as I know, it's not possible to specify the anchor of the node. So you need some dirty manual shifts so position it in the good way... And as soon as you change your drawing, you need to rechange the shift. Do you have a better way to position scopes? – tobiasBora Aug 13 '18 at 17:40
  • @tobiasBora Only very complicated ones. One thing you could do instead of the scope is to work with a path picture. This has an anchor but the coordinate system is not too intuitive to me. Another option is to use a pics. I have never tried to work with beamer overlays inside a pic, though. So this may or may not work. And if you really have only a few overlays, you'd need only a few saveboxes to make Max' nice answer do the job for you. Instead of overlays, you would then just show different saveboxe, but you won't be able to access the nodes in them. –  Aug 13 '18 at 17:47
4

Arrowheads are scaled by the line width (more or less), which is not scaled. Mostly because very thin lines are hard to see.

\documentclass[varwidth]{standalone}

\usepackage{tikz}

\begin{document}
Not scaled:
\begin{tikzpicture}[
    qubit/.style={draw, circle, color=black, anchor=center,
      fill={rgb,255:red,143;green,146;blue,237},
      inner sep=0pt,minimum width=5mm},
      line width=\pgflinewidth % default value
    ]
  \node[qubit] (q1) at (0,0){};
  \draw[red,-stealth] (q1.center) -- (q1.north);
\end{tikzpicture}


Scaled:
\begin{tikzpicture}[scale=.5, every node/.style={scale=.5},
    qubit/.style={draw, circle, color=black, anchor=center,
      fill={rgb,255:red,143;green,146;blue,237},
      inner sep=0pt,minimum width=5mm},
      line width=0.5\pgflinewidth
    ]
  \node[qubit] (q1) at (0,0){};
  \draw[red,-stealth] (q1.center) -- (q1.north);
\end{tikzpicture}
\end{document}

demo


Defaults:

\pgfdeclarearrow{
  name = Stealth,
  defaults = {
    length  = +3pt 4.5 .8,
    width'  = +0pt .75,
    inset'  = +0pt 0.325,
    line width = +0pt 1 1,
  },
John Kormylo
  • 79,712
  • 3
  • 50
  • 120
  • Thanks for the \pgflinewidth trick. Do you know what is the default value for arrow length, so that I can use -{Stealth[width=...,height=...]} to have perfect scale? – tobiasBora Aug 13 '18 at 15:33