1

I'm using pgfplots to draw data from csv files. For each line in the csv file, I'm adding a node (which possibly contains multiple lines of text) while keeping track of the y position. That means, I add a new node always above the previous one. A hopefully not too simplified minimum example:

\documentclass[a4paper,10pt]{article}
\usepackage[utf8]{inputenc}
\usepackage{tikz}
\usetikzlibrary{calc}
\usepackage{csvsimple}
\usepackage{pgfplots}
\usepgfplotslibrary{dateplot}
\usetikzlibrary{calc}
\pgfplotsset{compat=1.8}

\begin{document}
\begin{tikzpicture}
\begin{axis}[
date coordinates in=x,
date ZERO=2018-01-01,
xticklabel={\month.\year},
    xtick={
        2018-01-01 00:00, 
        2018-04-01 00:00, 
        2018-07-01 00:00, 
        2018-10-01 00:00
    },
    ymin=0,
    ymax=1,
    xmin=2018-01-01,
    xmax=2018-12-31,
    grid=both,
    only marks,
    axis x line=middle,
    axis y line=middle]
\draw (axis cs:2018-03-01, 0.2) node[anchor=west] (node1) {node 1 from csv file};
\draw (axis cs:2018-06-01, 0.4) node[anchor=west] (node2) {node 2 from csv file};
\draw (axis cs:2018-07-01, 0.8) node[anchor=west] {node $n$ from csv file};
\end{axis}
\draw (0,5) node {some more tikz drawings};
\end{tikzpicture}
\end{document}

In this simplified example, I set the y values manually.

The axis should in y direction be as high as the drawings. The axis y is specified by the ymax property. What I currently do, is to try out various values for ymax for each csv file. I guess I would be able to compute the correct value for ymax, but only after drawing the last node (in the example above, I would use the tikz node with height 5). But the ymax value needs to be set at the beginning.

My question: Can I somehow adjust the ymax, i.e., the axis height, at the end of/after the tikzpiture?

[My ideas: (i) somehow simulate all drawing to compute ymax, then go over everything again and draw. (ii) cut the tikzpicture after everything is drawn]

I appreciate any help, Bastian

EDIT: Thanks a lot for your help, marmot! I think my simplification didn't help but made things more confusing. So here is a more extended example what I'm actually doing. I am open to any more elegant solutions and comments to improve the code!

I have a csv file groups_data.csv

groupLabel, groupName
1, my group 1
2, my group 2

and a csv file subgroups.csv

groupLabel, subgroupDate, subgroupText
1, 2018-02-01, This is the first item of group 1
1, 2018-04-01, item 2
1, 2018-05-01, item with long text long text long text
2, 2018-02-01, next group

I do not want to modify the csv structure if there is any way around it. Now I want to plot the groups and subgroups in correct order:

\documentclass[a4paper,10pt]{article}
\usepackage[utf8]{inputenc}
\usepackage{tikz,fp}
\usetikzlibrary{calc}
\usepackage{csvsimple}
\usepackage{pgfplots}
\usepgfplotslibrary{dateplot}
\usetikzlibrary{calc}
\pgfplotsset{compat=1.8}

\newlength{\currentY}
\newcounter{numberofgroups}

% source: https://tex.stackexchange.com/questions/18389/tikz-node-at-same-x-coordinate-as-another-node-but-specified-y-coordinate
\makeatletter
\newcommand{\gettikzxy}[3]{%
  \tikz@scan@one@point\pgfutil@firstofone#1\relax
  \edef#2{\the\pgf@x}%
  \edef#3{\the\pgf@y}%
}
\makeatother

% source: https://tex.stackexchange.com/questions/38473/how-can-i-compute-the-distance-between-two-coordinates-in-tikz
\makeatletter
\def\calcLength(#1,#2)#3{%
\pgfpointdiff{\pgfpointanchor{#1}{center}}%
         {\pgfpointanchor{#2}{center}}%
\pgf@xa=\pgf@x%
\pgf@ya=\pgf@y%
\FPeval\@temp@a{\pgfmath@tonumber{\pgf@xa}}%
\FPeval\@temp@b{\pgfmath@tonumber{\pgf@ya}}%
\FPeval\@temp@sum{(\@temp@a*\@temp@a+\@temp@b*\@temp@b)}%
\FProot{\FPMathLen}{\@temp@sum}{2}%
\FPround\FPMathLen\FPMathLen5\relax
\global\expandafter\edef\csname #3\endcsname{\FPMathLen}
}
\makeatother

\def\xunitmatch{0.4}
\def\yunitmatch{100}

\begin{document}
\begin{tikzpicture}[x=\xunitmatch,y=\yunitmatch]
 \begin{axis}[
        anchor=origin,
        at={(0pt,0pt)},
        disabledatascaling,
        x=\xunitmatch,y=\yunitmatch,
        date coordinates in=x,
        date ZERO=2018-01-01,
        xticklabel={\month.\year},
        xtick={
        2018-01-01 00:00, 
        2018-04-01 00:00, 
        2018-07-01 00:00, 
        2018-10-01 00:00
        },
        ymin=0,
        ymax=1,
        xmin=2018-01-01,
        xmax=2018-12-31,
        grid=both,
        only marks,
        axis x line=middle,
        axis y line=none]

        \coordinate (axisleft) at (axis cs:2018-01-01,0);
        \coordinate (axisright) at (axis cs:2018-12-31,0);
        \csvreader[head to column names]{subgroups_data.csv}{}{
          \edef\subgroupXCoordinates{
            \noexpand\coordinate (xSubgroup\thecsvinputline) at (axis cs:\subgroupDate, 0);
          }
          \subgroupXCoordinates
        }
 \end{axis}
%set initial y value to draw groups and subgroups later
\coordinate (reference) at (0,0.05);
\gettikzxy{(reference)}{\ax}{\ay}
\setlength{\currentY}{\ay}

\gettikzxy{(axisleft)}{\axisleftx}{\axislefty}
\gettikzxy{(axisright)}{\axisrightx}{\axisrighty}


\setcounter{numberofgroups}{0}
% count the number of groups in the cvs file
\csvreader[head to column names]{groups_data.csv}{}    {\stepcounter{numberofgroups}}

% loop through all groups
\foreach \groupiter in {1,...,\value{numberofgroups}}{

% draw subgroups
  \csvreader[head to column names]{subgroups_data.csv}{}{
    \ifthenelse{\groupLabel=\groupiter}{
      % retrieve x position of subgroup
      \gettikzxy{(xSubgroup\thecsvinputline)}{\subgroupx}{\subgroupy}

      % calculate width of parbox for correct linebreak
      \coordinate (subgroupright) at (\axisrightx,0);
      \coordinate (subgroupleft) at (\subgroupx,0);
      \calcLength(subgroupleft,subgroupright){mylen}

      \draw (\subgroupx, \currentY) node[anchor=south west] (subgroupnode\thecsvinputline) {\parbox{\mylen pt}{\subgroupText}};
      \gettikzxy{(subgroupnode\thecsvinputline.north)}{\ax}{\ay}
      \setlength{\currentY}{\ay}
    }{}
  }


% draw group
  \csvreader[head to column names]{groups_data.csv}{}{
    \ifthenelse{\groupLabel=\groupiter}{
      \draw (10, \currentY) node[anchor=south] (groupnode\groupLabel) {\groupLabel};
      \gettikzxy{(groupnode\groupLabel.north)}{\ax}{\ay}
      \draw[fill=black] (\axisleftx, \ay) rectangle ($(\axisrightx, \ay)-(0,3ex)$);
      \draw[white] (10, \currentY) node[anchor=south] (groupnode\groupLabel) {\groupLabel};
      \setlength{\currentY}{\ay}
    }{}
  }
  \global\currentY=\currentY
}
 \end{tikzpicture}
\end{document}

So I only compute the x coordinates within the axis environment and do all drawing in plain tikz. I did this, because I could not get everything running within the axis environment (I think due to the fact macros are not evaluated immediately. This property seemed to make things more complex and not transparent to me). The result of the above code is fine, except the axis hight (vertical lines) is incorrect and would need manual adjustment for each set of csv files.

Any comments and help is really appreciated!

3
  • 1
    Welcome to TeX.SE! I am not sure I understand your question, but you do not have to set an ymax value. If you do not set it, pgfplots will make sure that all data points are shown.
    – user121799
    Sep 13, 2018 at 16:34
  • I didn't know that ymax is not required. Unfortunately, this does not directly fix my problem: if I unset ymax, no data is plotted in the example above. Furthermore, and probably more severely, I also do plotting in tikz after the axis environment which should be within the axis. (background: the code to plot is lengthy including e.g., for-loops. I couldn't fix all issues with \noxpand within axis, so I moved a significant part of the drawing outside of the axis). Any ideas? Please let me know if I can provide additional details to clarify.
    – Bastian
    Sep 13, 2018 at 17:06
  • Yes, because you do not use \addplot to plot the coordinates. If you use \addplot and place the nodes via nodes near coords, the size of the plots will automatically adjust. Of course, this is not true for tikz stuff that you add afterwards, but I am not sure that is necessary here. You may just use \addplot and nodes near coords.
    – user121799
    Sep 13, 2018 at 17:22

1 Answer 1

1

Here is a simple example without ymin and ymax. (You could use enlargelimits to enlarge the limits.)

\documentclass[a4paper,10pt]{article}
\usepackage[utf8]{inputenc}
\usepackage{tikz}
\usetikzlibrary{calc}
\usepackage{csvsimple}
\usepackage{pgfplots}
\usepgfplotslibrary{dateplot}
\usetikzlibrary{calc}
\pgfplotsset{compat=1.8}

\begin{document}
\begin{tikzpicture}
\begin{axis}[
date coordinates in=x,
date ZERO=2018-01-01,
xticklabel={\month.\year},
    xtick={
        2018-01-01 00:00, 
        2018-04-01 00:00, 
        2018-07-01 00:00, 
        2018-10-01 00:00
    },
    nodes near coords=node $\coordindex$ from csv file,
    xmin=2018-01-01,
    xmax=2018-12-31,
    grid=both,
    only marks,
    axis x line=middle,
    axis y line=middle]
\addplot coordinates {(2018-03-01, 0.2) 
(2018-06-01, 0.4) (2018-07-01, 0.8)};
\end{axis}
\draw (0,5) node {some more tikz drawings};
\end{tikzpicture}
\end{document}

enter image description here

I do not understand what some more tikz drawing will be.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .