1

I have two data files, one with measurement values (data.dat) and a second one with model data that describes how the values in data.dat are expected to behave (model.dat). Values in data.dat are added every now and then as they occur.

The values in model.dat span over a far greater x range than the measurement values in data.dat. Currently I limit the x axis to fit the data.dat values "manually" by setting an appropriate xmax value. However, it would be nice if the x axis range would be calculated automatically according to the data.dat values either by

  • ignoring the model.dat values for the axis range calculation or
  • telling pgfplots to calculate the axis range based on a certain plot or data file.

Is there such functionality in pgfplots?

Comment: Define different ranges for different data sets when plotting from a file or table might be loosely related or could be the way towards a workaround.

\begin{filecontents}{model.dat}
    x   y
    0   1
    1   0.8
    2   0.75
    3   0.72
    4   0.7
    5   0.69
\end{filecontents}
\begin{filecontents}{data.dat}
    x   y
    0   0.99
    1   0.81
    2   0.74
    3   0.70
\end{filecontents}

\documentclass{minimal}
\usepackage{pgfplots}

\begin{document}
    \begin{tikzpicture}
    \begin{axis}[xmax=4]
    \addplot table[x=x,y=y] {data.dat};
    \addplot table[x=x,y=y] {model.dat};
    \end{axis}
    \end{tikzpicture}
\end{document}
Benedikt Bauer
  • 6,590
  • 2
  • 34
  • 60

2 Answers2

2

This answer defines two functions that can be used here (and beyond): maxvalueofcolumnintable and minvalueofcolumnintable. For instance,

\pgfmathsetmacro{\mymax}{maxvalueofcolumnintable("x","data.dat")}

determines the maximal value of the x column in the table "data.dat", and stores it in the macro \mymax. This can then be used to define xmax.

\begin{filecontents}{model.dat}
    x   y
    0   1
    1   0.8
    2   0.75
    3   0.72
    4   0.7
    5   0.69
\end{filecontents}
\begin{filecontents}{data.dat}
    x   y
    0   0.99
    1   0.81
    2   0.74
    3   0.70
\end{filecontents}

\documentclass[tikz, margin=3mm]{standalone}
\usepackage{pgfplots}
\usepackage{pgfplotstable}
\pgfplotsset{compat=1.16}
\pgfmathdeclarefunction{maxvalueofcolumnintable}{2}{%
\begingroup
\pgfplotstablegetrowsof{#2}%
\pgfmathtruncatemacro{\numrows}{\pgfplotsretval-1}%
\pgfplotstablegetelem{0}{#1}\of{#2}%
\edef\pgfmathresult{\pgfplotsretval}%
\pgfplotsforeachungrouped\XX in{1,...,\numrows}{%
\pgfplotstablegetelem{\XX}{#1}\of{#2}%
\begingroup
\pgfkeys{/pgf/fpu,/pgf/fpu/output format=fixed}%
\pgfmathparse{max(\pgfmathresult,\pgfplotsretval)}%
\pgfmathsmuggle\pgfmathresult\endgroup
}%
\pgfmathsmuggle\pgfmathresult\endgroup  
}
\pgfmathdeclarefunction{minvalueofcolumnintable}{2}{%
\begingroup
\pgfplotstablegetrowsof{#2}%
\pgfmathtruncatemacro{\numrows}{\pgfplotsretval-1}%
\pgfplotstablegetelem{0}{#1}\of{#2}%
\edef\pgfmathresult{\pgfplotsretval}%
\pgfplotsforeachungrouped\XX in{1,...,\numrows}{%
\pgfplotstablegetelem{\XX}{#1}\of{#2}%
\begingroup
\pgfkeys{/pgf/fpu,/pgf/fpu/output format=fixed}%
\pgfmathparse{min(\pgfmathresult,\pgfplotsretval)}%
\pgfmathsmuggle\pgfmathresult\endgroup
}%
\pgfmathsmuggle\pgfmathresult\endgroup  
}

\begin{document}
    \begin{tikzpicture}
    \pgfmathsetmacro{\mymin}{minvalueofcolumnintable("x","data.dat")}
    \pgfmathsetmacro{\mymax}{maxvalueofcolumnintable("x","data.dat")}
    % just a test
    % \pgfmathsetmacro{\mytestmax}{maxvalueofcolumnintable("y","model.dat")}
    % \typeout{\mymax,\mytestmax}
    \begin{axis}[xmax=\mymax]
    \addplot table[x=x,y=y] {data.dat};
    \addplot table[x=x,y=y] {model.dat};
    \end{axis}
    \end{tikzpicture}
\end{document}

enter image description here

These functions can easily be generalize to average, standard deviations and so on, if needed.

2

This solution overlays two axis environments, both using the same scale (determined from the first axis only).

\begin{filecontents}{model.dat}
    x   y
    0   1
    1   0.8
    2   0.75
    3   0.72
    4   0.7
    5   0.69
\end{filecontents}
\begin{filecontents}{data.dat}
    x   y
    0   0.99
    1   0.81
    2   0.74
    3   0.70
\end{filecontents}

\documentclass{standalone}
\usepackage{pgfplots}

\makeatletter
\newcommand\getxycoords[2]{% #1=global macro for x, #2=global macro for y
    \pgfgetlastxy{#1}{#2}%
    \pgfmathparse{((#1/\pgfplots@x@veclength)+\pgfplots@data@scale@trafo@SHIFT@x)/10^\pgfplots@data@scale@trafo@EXPONENT@x}%
    \global\let #1=\pgfmathresult
    \pgfmathparse{((#2/\pgfplots@y@veclength)+\pgfplots@data@scale@trafo@SHIFT@y)/10^\pgfplots@data@scale@trafo@EXPONENT@y}
    \global\let #2=\pgfmathresult}
\makeatother

\newcommand{\xmin}{}% reserve gobal names
\newcommand{\xmax}{}
\newcommand{\ymin}{}
\newcommand{\ymax}{}

\begin{document}
    \begin{tikzpicture}
    \begin{axis}[scale only axis]
    \addplot table[x=x,y=y] {data.dat};
    \pgfplotsextra{%
      \path (rel axis cs: 0,0);% lower left corner
      \getxycoords{\xmin}{\ymin}%
      \path (rel axis cs: 1,1);% upper right corner
      \getxycoords{\xmax}{\ymax}}%
    \end{axis}
    \node[below right] at (current bounding box.south west) {xmin=\xmin, ymin=\ymin, xmax=\xmax, ymax=\ymax};
    \begin{axis}[scale only axis, axis x line=none, axis y line=none,
                 xmin=\xmin, ymin=\ymin, xmax=\xmax, ymax=\ymax]
    \addplot coordinates {};% do nothing
    \addplot table[x=x,y=y] {model.dat};
    \end{axis}
    \end{tikzpicture}
\end{document}

demo

John Kormylo
  • 79,712
  • 3
  • 50
  • 120
  • Would you mind adding some explanation for the idea behind the two axes? I'd like to understand your solution but don't get the idea. – Benedikt Bauer Feb 24 '20 at 19:49
  • You set the scale using the \addplots in the first axis environment, then use the same scale to display the \addplots in the second axis environment. – John Kormylo Feb 25 '20 at 02:58