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!
ymax
value. If you do not set it, pgfplots will make sure that all data points are shown.\addplot
to plot the coordinates. If you use\addplot
and place the nodes vianodes near coords
, the size of the plots will automatically adjust. Of course, this is not true fortikz
stuff that you add afterwards, but I am not sure that is necessary here. You may just use\addplot
andnodes near coords
.