2

I found some answer here about how to get ymin/ymax automatically calculated by pgfplots. One can add to axis settings after end axis/.code={\pgfmathsetmacro{\hi}{\pgfkeysvalueof{/pgfplots/ymax}}} and similarly for ymin. My MWE is:

\RequirePackage{luatex85}
\documentclass{standalone}
\usepackage{pgfplots}
\pgfplotsset{compat=1.15}
\usetikzlibrary{calc}

\begin{document}

\def\xmi{0}
\def\xma{3.5}

\begin{tikzpicture}
\begin{axis}[xlabel={x},ylabel={y}, no markers, samples=100, clip mode=individual, xmin=\xmi, xmax=\xma, restrict x to domain=\xmi:\xma,
after end axis/.code={
\pgfmathsetmacro{\hi}{\pgfkeysvalueof{/pgfplots/ymax}};
\pgfmathsetmacro{\lo}{\pgfkeysvalueof{/pgfplots/ymin}};
\xdef\hhi{1.2*\hi}; % tried this, but it gives error further in node{test}
\fill[green] ($(\xmi,\hi + 0.05*\hi - 0.05*\lo)$) rectangle ($(\xma,\hi + 0.1*\hi - 0.1*\lo)$);
\node at (\xma/2,\hi) {node1};
}
]

\addplot {6*sin(deg(x))};

\node at (2,8) {text};

%\node at ($(\xma/2, \hhi)$) {test}; % this gives error

\end{axis}
\end{tikzpicture}
\end{document}

I see no green rectangle above figure, and {node1} is in wrong position. Also commented node {test} gives error. Why sin don't start from x=0 exactly? I saw also that using restrict ... may change whole picture. Where am I wrong? Thank you.

chunga
  • 23
  • 3
  • The green rectangle is quite small, and ends up on top of the tick for y=-2. Regarding the last question: the default domain is -5:5, and with 100 samples you get a point at x=-0.05, and the next one at x=0.05. You probably want domain=\xmi:\xma here, not restrict x to domain. Also, what's the purpose of the ($(...)$), you're not doing anything that requires the $ syntax of the calc library. – Torbjørn T. Jan 31 '18 at 08:56
  • @TorbjørnT. yes, green rectangle is small, but it should be from \xmi to \xma and its height should be 0.05*(vertical size of graph). ($(...)$) are used in coordinates (of rectangle and nodes), is this wrong? – chunga Jan 31 '18 at 09:08
  • The dollar sign stuff is completely unnecessary. I don't know exactly why the green rectangle ends up where it does in your code, though, it's possible they are read as lengths in points, so you get for example an x-component of 3.5pt for the end point of the rectangle. – Torbjørn T. Jan 31 '18 at 09:20

1 Answers1

2

Seems you actually need axis cs to use axis coordinates in after end axis, even with compat=1.15. You do not however need the dollar signs in coordinates, they are not required to do arithmetic in the components of a coordinate, like you do. (Read section 13.5 in the TikZ manual to see what you can use that syntax for.)

The green rectangle does show up in your code as well. I suspect that the components of the coordinates are read as lengths in points. Hence, the the end point of the rectangle, for example, is placed at approximately (3.5pt, 7.8pt).

Regarding the \xdefed macro, I think you're trying to use it at a time when it is not yet been defined, \hhi will only be available after \end{axis}. (Where it will expand to 1.2*6.80955100000, and not the resulting value of that calculation, of course.)

Finally, the reason your sine curve doesn't start at zero, is a very common cause of confusion. The default domain is -5:5, and with 100 samples you get a point at x=-0.05, and the next one at x=0.05. Because of your restrict x to domain setting, the one at -0.05 is discarded (well, set to -inf, actually), and the curve thus starts at 0.05. Here you probably want to use domain=\xmi:\xma instead of restrict to domain.

output of code

\RequirePackage{luatex85}
\documentclass{standalone}
\usepackage{pgfplots}
\pgfplotsset{compat=1.15}

\newcommand\xmi{0}
\newcommand\xma{3.5}
\begin{document}
\begin{tikzpicture}
\begin{axis}[
  xlabel={x},
  ylabel={y},
  no markers,
  samples=100,
  clip=false,
  xmin=\xmi,
  xmax=\xma,
  domain=\xmi:\xma,
  after end axis/.code={
    \pgfmathsetmacro{\hi}{\pgfkeysvalueof{/pgfplots/ymax}};
    \pgfmathsetmacro{\lo}{\pgfkeysvalueof{/pgfplots/ymin}};
    % note axis cs: in the coordinates in the next two lines
    \fill[green,ultra thick] (axis cs:\xmi,\hi+0.05*\hi-0.05*\lo) rectangle (axis cs:\xma,\hi+0.1*\hi-0.1*\lo);
    \node at (axis cs:\xma/2,\hi) {node1};
  }
]

\addplot {6*sin(deg(x))};

\node at (2,8) {text};

\end{axis}
\end{tikzpicture}
\end{document}

Alternative

A couple of different approaches to drawing a rectangle like that, using the features of the calc library. This relies on giving the axis a name, so that its anchors can be accessed.

output of second code block

\RequirePackage{luatex85}
\documentclass[border=5mm]{standalone}
\usepackage{pgfplots}
\pgfplotsset{compat=1.15}
\usetikzlibrary{calc}

\newcommand\xmi{0}
\newcommand\xma{3.5}
\begin{document}
\begin{tikzpicture}
\begin{axis}[
  % note addition of name=ax
  name=ax,
  xlabel={x},
  ylabel={y},
  no markers,
  samples=100,
  xmin=\xmi,
  xmax=\xma,
  domain=\xmi:\xma,
]

\addplot {6*sin(deg(x))};

\node at (2,8) {text};
\end{axis}

\path
 % the let syntax requires \usetikzlibrary{calc}
 let
  % with \p1=(ax.south west), the x-component of the coordinate of
  % the bottom left corner of the axis is available in \x1,
  % and the y-component in \y1
  \p1=(ax.south west),
  % similarly for the top right corner
  \p2=(ax.north east),
  % the value of a calculation can be saved to \n{<something>}
  \n1={0.05*(\y2-\y1)}
  % note that the macros defined above are not available
  % outside this specific path
  in
  % save coordinates for the rectangle
  % (you could also have used \fill let ... (\x1,\y2+\n1) rectangle (\x2,\y2+2*\n1); directly)
  coordinate (lowerleft) at (\x1,\y2+\n1)
  coordinate (upperright) at (\x2,\y2+2*\n1)
;

\fill[green] (lowerleft) rectangle (upperright);

% the anchors of the axis can be used to place stuff
\node at (ax.north) {node1};

% another possibility, again with the calc-library
% ($(ax.south west)!1.15!(ax.north west)$) is using a "partway modifier"
% draw a line from ax.south west to ax.north west, then make it 15% longer
% (multiply length by 1.15), this coordinate is at that point
\fill [blue] ($(ax.south west)!1.15!(ax.north west)$) rectangle 
             ($(ax.south east)!1.2!(ax.north east)$);
\end{tikzpicture}
\end{document} 

Alternative 2

There is the rel axis cs coordinate system, which lets you specify coordinates as fractions of the axis coordinate system. (rel axis cs:0,0) is the bottom left of the axis, (rel axis cs:1,1) is the top right.

rel axis cs can be combined with axis cs coordinates using a perpendicular coordinate specification, see point 1 in TikZ: What EXACTLY does the the |- notation for arrows do?, and example in code below.

output of third code block

\RequirePackage{luatex85}
\documentclass[border=5mm]{standalone}
\usepackage{pgfplots}
\pgfplotsset{compat=1.15}
\usetikzlibrary{calc}

\newcommand\xmi{0}
\newcommand\xma{3.5}
\begin{document}
\begin{tikzpicture}
\begin{axis}[
  % note addition of name=ax
  name=ax,
  xlabel={x},
  ylabel={y},
  no markers,
  clip mode=individual,
  samples=100,
  xmin=\xmi,
  xmax=\xma,
  domain=\xmi:\xma,
]

\addplot {6*sin(deg(x))};

\node at (2,8) {text};

% you can use relative axis coordinates
\fill [green] (rel axis cs:0,1.05) rectangle (rel axis cs:1,1.1);

% to combine relative and explicit coordinates
\fill [red] ({rel axis cs:0,1.15} -| {axis cs:0.5,0}) % y-component of (rel axis cs:0,1.15), x-component of (axis cs:0.5,0)
            rectangle
            ({rel axis cs:0,1.2} -| {axis cs:2,0});

\fill [blue] ({rel axis cs:0,1.15} -| {axis cs:2.5,0}) rectangle
              ({rel axis cs:0,1.2} -| {axis cs:\xma,0});
\end{axis}
\end{tikzpicture}
\end{document} 
Torbjørn T.
  • 206,688
  • Many thanks! So, if I want to place some objects/nodes above the graph and make their size be a fraction of whole picture size I need do this all inside after end axis, right? – chunga Jan 31 '18 at 09:19
  • @chunga Well, you could also calculate the size of the axis after \end{axis}, using the let syntax (see chapter 14.15 in the TikZ manual). I'll add an example of that in a bit. – Torbjørn T. Jan 31 '18 at 09:22
  • @chunga See updated answer. – Torbjørn T. Jan 31 '18 at 09:45
  • Tried let constructions. This \fill [red] let \p1=(ax.south west), \p2=(ax.north west), \n1={0.05*(\y2-\y1)}, \n2={0.1*(\y2-\y1)} in (2.04,\y2+\n1) rectangle (3.3,\y2+\n1+\n2); gives red rectangle, but with wrong x coordinates. :( Using axis cs: gives error ... missing \endcsname – chunga Jan 31 '18 at 10:27
  • @chunga Why do you use 2.04 and 3.3? Note that all of that is after \end{axis}, so you can't use axis coordinates directly. – Torbjørn T. Jan 31 '18 at 10:29
  • Sorry for stupidity, but how to place several objects with different x coordinates and the same y coordinate, that depends on unknown in advance ymax? I thought I can define somehow constants (that value y), and then use many \fill and \draw like \fill [red] (2.04, <y1_constant>) rectangle (3.3, <y2_constant>), probably inside axis ... – chunga Jan 31 '18 at 10:38
  • In gnuplot it can be done simple: one set tmargin and then set objects with at screen coordinates. – chunga Jan 31 '18 at 10:41
  • @chunga I don't know Gnuplot very well, but sounds a bit like the rel axis cs coordinate system. Exactly what kind of relation do you want between the coordinates of the new objects, and the coordinates of the axis? Relative to the range, or explicit axis values? Put differently, what numbers do you want to input, for what kind of result? – Torbjørn T. Jan 31 '18 at 10:50
  • Great! Your Alternative 2 is exactly what I mean, so I accept this your answer. rel axis cs is analog of screen coordinates in gnuplot, but in pgfplots we don't need reserve space above the graph as with set tmargin in gnuplot, one just say clip mode= individual. Many thanks. – chunga Jan 31 '18 at 11:42