# Keep zero in the centre of axis

I want to understand if I can keep the x axis automatically "centred" around 0, i.e., having the absolute axis option values for x min and x max equal, without setting them explicitly.

The following MWE shows the issue. I have point estimates and their confidence intervals. The maximum values are -3.5 and 3.5, however, setting those to x min or x max would decrease the readability (shrink the plots). On the other hand, comparing the point estimates would be easier if the zero was centred.

# MWE:

\documentclass{article}

\usepackage{pgfplots}

\begin{filecontents}{data.csv}
nr est CL CU
1 -0.9 -1.3 -0.3
2 0 -0.6 0.58
\end{filecontents}

\begin{document}

\begin{tikzpicture}
\begin{axis}[xmajorgrids]
\addplot+[only marks,error bars/.cd,x explicit,x dir=both] table [
x=est,
y = nr,
x error plus expr=\thisrow{CU}-\thisrow{est},
x error minus expr=\thisrow{est}-\thisrow{CL}]{data.csv};
\end{axis}
\end{tikzpicture}

\end{document}


I am not sure if there is an automatic solution since \pgfkeysvalueof{/pgfplots/xmin} and \pgfkeysvalueof{/pgfplots/xmax} won't be set but it is easy to infer the actual values of xmin and xmax using calc. They can be used in the final plot.

\documentclass{article}
\usepackage{filecontents}
\begin{filecontents*}{data.csv}
nr est CL CU
1 -0.9 -1.3 -0.3
2 0 -0.6 0.58
\end{filecontents*}
\usepackage{pgfplots}
\usetikzlibrary{calc}
\pgfplotsset{compat=1.16}

\begin{document}
Step 1: measure the $x_\mathrm{min}$ and $x_\mathrm{max}$ used in the plot.

\begin{tikzpicture}
\begin{axis}[xmajorgrids]
\addplot+[only marks,error bars/.cd,x explicit,x dir=both] table [
x=est,
y = nr,
x error plus expr=\thisrow{CU}-\thisrow{est},
x error minus expr=\thisrow{est}-\thisrow{CL}]{data.csv};
\path (0,0) coordinate (O) (1,0) coordinate(X);
\end{axis}
\path let \p1=($(current axis.west)-(O)$),\p2=($(current axis.east)-(O)$),
\p3=($(X)-(O)$) in
\pgfextra{\pgfmathsetmacro{\myxmin}{\x1/\x3}%
\pgfmathsetmacro{\myxmax}{\x2/\x3}%
\message{xmin=\myxmin, xmax=\myxmax^^J}%
\pgfmathsetmacro{\newxmin}{-1*max(abs(\myxmin),abs(\myxmax))}%
\xdef\newxmin{\newxmin}%
\pgfmathsetmacro{\newxmax}{max(abs(\myxmin),abs(\myxmax))}%
\xdef\newxmax{\newxmax}};
\end{tikzpicture}

Step 2: measure the $x_\mathrm{min}$ and $x_\mathrm{max}$ used in the plot.

\begin{tikzpicture}
\begin{axis}[xmajorgrids,xmin=-1.488,xmax=1.488]
\addplot+[only marks,error bars/.cd,x explicit,x dir=both] table [
x=est,
y = nr,
x error plus expr=\thisrow{CU}-\thisrow{est},
x error minus expr=\thisrow{est}-\thisrow{CL}]{data.csv};
\end{axis}
\end{tikzpicture}

\clearpage
You can also use the computed values.

\begin{tikzpicture}
\begin{axis}[xmajorgrids,xmin=\newxmin,xmax=\newxmax]
\addplot+[only marks,error bars/.cd,x explicit,x dir=both] table [
x=est,
y = nr,
x error plus expr=\thisrow{CU}-\thisrow{est},
x error minus expr=\thisrow{est}-\thisrow{CL}]{data.csv};
\end{axis}
\end{tikzpicture}

\end{document}


You may make it fully automatic by writing the inferred values to the aux file. I will be happy to spell this out if needed. ADDENDUM: Here is a version that does that.

\documentclass{article}
\usepackage{filecontents}
\begin{filecontents*}{data.csv}
nr est CL CU
1 -0.9 -1.3 -0.3
2 0 -0.6 0.58
\end{filecontents*}
\usepackage{pgfplots}
\usetikzlibrary{calc}
\pgfplotsset{compat=1.16}

\makeatletter
\newcommand{\ExportXmaxmin}{\immediate\write\@mainaux{\xdef\string\newxmin{\newxmin}\relax%
\xdef\string\newxmax{\newxmax}\relax}}
\makeatother

\begin{document}
\begin{tikzpicture}
\ifdefined\newxmin
\message{Read xmin=\newxmin\space and xmin=\newxmax\space from aux file.^^J}
\else
\message{Compile the document again to get the adjusted xmin and xmax values.^^J}
\fi

\addplot+[only marks,error bars/.cd,x explicit,x dir=both] table [
x=est,
y = nr,
x error plus expr=\thisrow{CU}-\thisrow{est},
x error minus expr=\thisrow{est}-\thisrow{CL}]{data.csv};
\path (0,0) coordinate (O) (1,0) coordinate(X);
\end{axis}
\ifdefined\newxmin
\else
\path let \p1=($(current axis.west)-(O)$),\p2=($(current axis.east)-(O)$),
\p3=($(X)-(O)$) in
\pgfextra{\pgfmathsetmacro{\myxmin}{\x1/\x3}%
\pgfmathsetmacro{\myxmax}{\x2/\x3}%
\pgfmathsetmacro{\newxmin}{-1*max(abs(\myxmin),abs(\myxmax))}%
\pgfmathsetmacro{\newxmax}{max(abs(\myxmin),abs(\myxmax))}%
\ExportXmaxmin};
\fi
\end{tikzpicture}
\end{document}

• Of course one also put the trial plot in a savebox. – Schrödinger's cat Aug 31 '19 at 20:49
• Thank you for that cool answer! For not explcitily setting x min/x max you outline to options, 1) writing calculated values to the aux file and 2) put the trial into a savebox? I think I can do option 2) myself. I am puzzled with 1) though. If you can provide that, that'd be cool. – Marcus Sep 1 '19 at 10:29
• @Marcus I added a version that does that. As usual, whenever one has to use \makeatletter, this means we are likely entering terrain in which one has to be more careful. One shortcoming of this version is that it does not support more than one symmetric axis. This can be fixed, of course, but only at the expense of making the code even more complex. (One needs to add a counter to be able to connect the new xmin and xmax values to a given axis.) Extending this to the y direction is straightforward. – Schrödinger's cat Sep 1 '19 at 14:08
• that was all helpful thank you, I also learnt some more bits about macros. – Marcus Sep 1 '19 at 14:30
• @Marcus One strategy is to make \newxmin and \newxmax depend on the figure. One could introduce a counter, but this will become messy if you add a new figure in the chain. So you may give these your own names like \newxminA and \newxmaxA and so on.This can be made a style with execute at begin picture, execute at end axis and similar keys, and some \expandafter\csname newxmax#1\endcsname tricks. (I am not an expert on \includestandalone. If you ask a new question, this may receive Martin Scharrer's attention.) – Schrödinger's cat Sep 1 '19 at 14:39