1

From my previous question/answer Tikz image within a defined box (& the textpos package), @frougon provided a great solution. And now, I'm seeking to have a standard scaling for all of my Tikz-pictures (see the edit/addition).

I want all of my Tikz-pictures to be 3.5cm x 3.5cm, and I can do this by using scale = 3.5/k, where k is the "coordinate-length" of the Tikz-picture.

I'm wondering if there is a way to get the outermost (or length of) coordinates in a Tikz-picture? For example,

\begin{tikzpicture}
    \draw (1,4)--(10,7);
\end{tikzpicture}

would have k=9, as the x-axis ranges from 1 to 10 (a difference of 9), while the y=axis ranges from 4 to 7 (a difference of 3).

I would envision some sort of "maximum" function coming into play here. Something like k = max(<largest x coordinate> - <smallest x coordinate >, <largest y coordinate > - <smallest y coordinate >) = max(10-1,7-4) = max(9,3) = 9.

For a more detailed example, consider the following:

\begin{tikzpicture}
    \draw[thick] (0,0)--(10,5);
    \draw[thick] (0,0)--(5,-10);
    \draw[thick] (0,0)--(-10,5);
    \draw[thick] (0,0)--(-5,-10);
    \draw[thick] (0,0)--(10,-5);
    \draw[thick] (0,0)--(-5,10);
    \draw (.5,2) node {1};
    \draw (-2.5,2.5) node {2};
    \draw (-2,-.5) node {3};
    \draw (0,-2.5) node {4};
    \draw (2.5,-2.5) node {5};
    \draw (2.5,0) node {6};
\end{tikzpicture}

In this case, I would want k = 20, as the "length" of the x-axis (and y-axis, in fact), is 20 coordinate units.

Thanks in advance!

ryanj1823
  • 301

2 Answers2

4

UPDATE: This computes the dimensions of the bounding box and the corresponding scale factor, which it applies in the next run. (Replaced max by min, big thanks to frougon!)

\documentclass[tikz,border=3.14mm]{standalone}
\usetikzlibrary{calc}
\makeatletter
\newcommand\ExportBB[1]{\path let 
 \p1=($(current bounding box.north east)-(current bounding box.south west)$),
 \n1={#1/\x1},\n2={#1/\y1}
 in \pgfextra{\pgfmathsetmacro{\figscale}{min(\n1,\n2)}\xdef\figscale{\figscale}};
 \immediate\write\@mainaux{\xdef\string\figscale{\figscale}\relax}}
\makeatother
\tikzset{scale to max size/.style={execute at end picture={\ExportBB{#1}},
/utils/exec=\ifdefined\figscale
\else
\message{Recompile the figure.}
\xdef\figscale{1}
\fi,scale=\figscale}}
\begin{document}
\begin{tikzpicture}[scale to max size=3.5cm]
    \draw[thick] (0,0)--(10,5);
    \draw[thick] (0,0)--(5,-10);
    \draw[thick] (0,0)--(-10,5);
    \draw[thick] (0,0)--(-5,-10);
    \draw[thick] (0,0)--(10,-5);
    \draw[thick] (0,0)--(-5,10);
    \draw (.5,2) node {1};
    \draw (-2.5,2.5) node {2};
    \draw (-2,-.5) node {3};
    \draw (0,-2.5) node {4};
    \draw (2.5,-2.5) node {5};
    \draw (2.5,0) node {6};
\end{tikzpicture}
\end{document}

enter image description here

Of course, the texts are not transformed. You could transform them, too, but then it might be more straightforward to use \maxsizebox{3.5cm}{3.5cm}{....} that comes with adjustbox.

This stores the dimensions in \n1 and \n2 in the first example and prints the dimensions in a node in the second example.

\documentclass[tikz,border=3.14mm]{standalone}
\usetikzlibrary{calc}
\begin{document}
\begin{tikzpicture}
    \draw (1,4)--(10,7);
    \path let \p1=($(current bounding box.north east)-(current bounding
    box.south west)$),\n1={\x1/1cm},\n2={\y1/1cm}
    in \pgfextra{\typeout{x=\n1 cm,y=\n2 cm}};
\end{tikzpicture}

\begin{tikzpicture}[store dimensions of current picture in/.style 2 args={
  insert path={let \p1=($(current bounding box.north east)-(current bounding
    box.south west)$),\n1={\x1/1cm},\n2={\y1/1cm}
    in \pgfextra{\edef#1{\n1}\edef#2{\n2}}}}]
    \draw[thick] (0,0)--(10,5);
    \draw[thick] (0,0)--(5,-10);
    \draw[thick] (0,0)--(-10,5);
    \draw[thick] (0,0)--(-5,-10);
    \draw[thick] (0,0)--(10,-5);
    \draw[thick] (0,0)--(-5,10);
    \draw (.5,2) node {1};
    \draw (-2.5,2.5) node {2};
    \draw (-2,-.5) node {3};
    \draw (0,-2.5) node {4};
    \draw (2.5,-2.5) node {5};
    \draw (2.5,0) node {6};
    \path[store dimensions of current picture in={\myx}{\myy}]
    node[fill=white] at (current bounding box.center) {%
    $x=\pgfmathparse{\myx}\pgfmathprintnumber{\pgfmathresult}$cm,
    $y=\pgfmathparse{\myy}\pgfmathprintnumber{\pgfmathresult}$cm};
\end{tikzpicture}
\end{document}

enter image description here

  • I would like to take the maximum of these lengths and scale the tikzpicture by 3.5/maximum. Also, I'm confused how \n1 and \n2 are actually stored and how I would scale the picture (something like \begin{tikzpicture}[scale = 3.5/max{\n1, \n2}) – ryanj1823 Jun 28 '19 at 06:21
  • @ryanj1823 You cannot know at the beginning of the tikzpicture how large it will be. However, adustbox allows you to do precisely that, it has some maximum functions of that type. –  Jun 28 '19 at 06:24
  • ...and of course you did my "difficult solution" in almost no time. marmots rocks! – Rmano Jun 28 '19 at 06:54
  • @Rmano I was prepared: https://tex.stackexchange.com/a/497592/121799. –  Jun 28 '19 at 06:55
  • @marmot Interesting! 1) Despite what the OP wrote, I bet what he really wants is desired/min(\n1,\n2), not max, otherwise the scaled picture will be either larger or taller than the frame, unless it has a 1:1 aspect ratio (which is the case in the example used here!). 2) I implemented this at the box level (requiring only one pass) in my answer to his original question once I understood that was desired, but I believe he... – frougon Jun 28 '19 at 19:13
  • @marmot... didn't connect yet since then, so couldn't say if this actually does what he wants. There is one significant difference between our techniques, though: mine will scale fonts in the tikzpictures whereas yours won't, as you said (he can use yours with my code, then there should be no font scaling and all should still work). – frougon Jun 28 '19 at 19:15
  • 1
    @frougon Yes, that's a nice answer (+1). However, let me mention that there is a second difference: if you use scalebox, adjustbox etc., you can no longer access coordinates with remember picture. In many situations this won't matter, but in some it does. –  Jun 28 '19 at 19:18
  • @marmot Thanks for the complements! I added a paragraph about this (not published yet) but have one question: if the OP prepares a picture that has remember picture using your technique, my code will apply 1:1 scaling using \scalebox (that is, if you fix yours to use min :-). Is such 1:1 scaling going to break the remember picture mechanism, or not? If yes, I'll provide an option to disable automatic scaling for the pictures where it is undesirable. (I will try it if you don't know the answer by heart, of course) – frougon Jun 28 '19 at 19:40
  • @frougon I think 1:1 will work but I am sure that for other values it generically breaks. (This is one the of the most important drawbacks when solving the "do-not-nest-tikzpicture" issue with saveboxes, and which is why there things like subnodes by LoopSpace are really cool.) –  Jun 28 '19 at 20:11
  • @frougon I agree that min is better and corrected it, thanks! –  Jun 28 '19 at 20:43
  • 1
    @frougon I think that this is just a numerical inaccuracy because the symbolic coordinates are stored internally in pt units, so TikZ converts back and forth and loses the edges. Try e.g. \documentclass[tikz, border=3.14mm]{standalone} \usetikzlibrary{calc} \begin{document} \path let \p1=($(A)-(1,5)$) in \pgfextra{\typeout{\x1,\y1}}; \end{tikzpicture} \end{document}. We probably need to live with these limitations. –  Jun 28 '19 at 22:38
  • @marmot Sorry, I removed my comments about this because I found out this was a known issue concerning grid, so I had the impression I was only polluting this discussion with some problem not really relevant (now that I know it was not due to your code). Unrelated: I've added support for the noscale option in my code. To be more useful for real-word usage, I believe your code should accept a parameter used as prefix or suffix for the control sequence... – frougon Jun 28 '19 at 22:41
  • ... (currently \figscale) written to the .aux file. Otherwise, only one figure per document can use this mechanism. Also, I don't know why you put \relax after the definition in the .aux file. – frougon Jun 28 '19 at 22:44
  • @frougon Yes, it is true that it only works for one figure in its present form, and I used \relax because LaTeX does not understand \hibernate. ;-) –  Jun 29 '19 at 00:17
  • @marmot I thought you had \let\hibernate\relax in the marmotTeX format. ;-) More seriously, I've extended your style a little bit (mainly: to allow several pictures per document and a target frame that isn't necessarily a square). You can see the short description and the code in my answer. – frougon Jun 29 '19 at 12:11
  • @marmot The noscale option I mentioned above has been renamed to autoscale=false (the corresponding argument is now processed with l3keys). In case the OP wants autoscale=false to be the default (probably in order to use your scaling technique most of the time), it can be done with a one-word change that is described in my already-linked answer. – frougon Jun 29 '19 at 12:16
1

This seems to me a kind of XY question... I am not sure about the exact semantic you want, but for example:

\documentclass{article}
\usepackage[T1]{fontenc}
\usepackage[utf8]{inputenc}
\usepackage{tikz}
\usepackage{adjustbox}
\begin{document}
\adjustboxset{min width=3.5cm, min height=3.5cm, max width=3.5cm, max height=3.5cm}

\adjustbox{}{\tikz \draw (0,0) rectangle (4,6) (2,2) rectangle (3,3);}
\adjustbox{}{\tikz \draw (0,0) rectangle (6,4) (2,2) rectangle (3,3);}
\adjustbox{}{\tikz \draw (0,0) rectangle (6,6) (2,2) rectangle (3,3);}
\adjustbox{}{\tikz \draw (0,0) rectangle (1,1) (.2,.2) rectangle (.3,.3);}
\end{document}

will produce: enter image description here

which can or cannot be what you want (notice the effect of scaling on the smaller picture).

Otherwise, the only other way I see is using @marmot answer, and doing a bit of magic to store the scale factor in the .aux file to be used at the second pass. (Too complex now to think about it, no time...)

Rmano
  • 40,848
  • 3
  • 64
  • 125