Take the 2-minute tour ×
TeX - LaTeX Stack Exchange is a question and answer site for users of TeX, LaTeX, ConTeXt, and related typesetting systems. It's 100% free, no registration required.

I am making a pgfplots stacked xbar plot where each bar has a distinct label, in addition to a numeric bar length. Each pair of bars also has a common label. I would like to mark each bar with its distinct label and its length, and mark each pair of bars with their common label.

Two parts to my question (EDIT: (1) is answered in 3):

  1. how to avoid defining the extra Score-name column (see MWE below), and instead compute it from the Score and Name columns in the table? EDIT: according to the package author (answer to 3), there is no built-in support for this, but it's on his TODO list. EDIT 2013-3-25: according to answer below, this is now supported.

  2. how to make the computed labels appear on the right y axis, instead of at the end of the bars?

I don't know the best way to depict the data, but per bar extra y tick labels, as in Jake's answer to another question would probably be good.

I couldn't figure out how to get per bar extra y tick labels, but I have alternate solution where the label placement is not as good: add an extra column to the input data table and use it for the per-bar labels. Problems with this solution include: having to add the extra column; not being able to use the pgfplots command to format the numeric part of the labels from the extra column (illustrated below); and (subjectively) that it doesn't look as good as extra u tick labels would.

My MWE (also based on Jake's answer to another question. Thanks Jake!) has two figures. The first figure shows my solution by manually adding the Score-name column, and the second figure shows how the numeric formatting directives (i.e. scientific notation) are not being honored in that first figure (which seems natural, because Score-name is not numeric).

\documentclass{article}
\usepackage{pgfplots}
\usepackage{filecontents}
\pgfplotsset{compat=newest}

\begin{filecontents}{data1.dat}
Age-interval  Y-Position  Score   Name  Score-name
20-30         1           0.15    Peter {0.15 (Peter)}
30-40         2           0.20    Jeff  {0.20 (Jeff)}
40-50         3           0.12    Steve {0.12 (Steve)}
50-60         4           1.24    John  {0.24 (John)}
\end{filecontents}

\begin{filecontents}{data2.dat}
Age-interval  Y-Position  Score    Name    Score-name
20-30         1           0.159    Peeteer {0.159 (Peeteer)}
30-40         2           0.209    Jeeff   {0.209 (Jeeff)}
40-50         3           0.129    Steevee {0.129 (Steevee)}
50-60         4           1.249    Joohn   {0.249 (Joohn)}
\end{filecontents}


\begin{document}

\begin{tikzpicture}
\begin{axis}[
    xlabel={The \texttt{format/sci} is ignored below, but the \texttt{font=\textbackslash{}small} is obeyed below:},
    xbar,     
    %bar width=2pt,
    ytick=data,
    width=8 cm,
    height=6 cm,
    enlarge y limits={true, value=0.2},
    xmin=-0.01,
    xmax = 2.0,
    xticklabel pos = upper,
    tick align = outside,
    yticklabel pos=left, 
    yticklabels from table={data.dat}{Age-interval},
    %ylabel={Age intervals (yr)},
    nodes near coords,
    every node near coord/.append style={
      anchor=west,
      font=\small,
      % This format/sci gets ignored, because the Score-name is not a
      % number:
      /pgf/number format/sci,
      %/pgf/number format/zerofill,
      /pgf/number format/precision=2,
    },
    point meta=explicit symbolic
]
\addplot table [
    y=Y-Position,
    x=Score,
    meta=Score-name
] {data1.dat};
\addplot table [
    y=Y-Position,
    x=Score,
    meta=Score-name
] {data2.dat};

\end{axis}
\end{tikzpicture}

\begin{tikzpicture}
\begin{axis}[
    xlabel={Both the \texttt{format/sci} and the \texttt{font=\textbackslash{}small} are obeyed below:},
    xbar,     
    %bar width=2pt,
    ytick=data,
    width=8 cm,
    height=6 cm,
    enlarge y limits={true, value=0.2},
    xmin=-0.01,
    xmax = 2.0,
    xticklabel pos = upper,
    tick align = outside,
    yticklabel pos=left, 
    yticklabels from table={data.dat}{Age-interval},
    %ylabel={Age intervals (yr)},
    nodes near coords,
    every node near coord/.append style={
      anchor=west,
      font=\small,
      % This format/sci gets ignored, because the Score-name is not a
      % number:
      /pgf/number format/sci,
      %/pgf/number format/zerofill,
      /pgf/number format/precision=2,
    },
    % THIS IS UNCOMMENTED ABOVE
    %point meta=explicit symbolic
]
\addplot table [
    y=Y-Position,
    x=Score,
    meta=Score-name
] {data1.dat};
\addplot table [
    y=Y-Position,
    x=Score,
    meta=Score-name
] {data2.dat};

\end{axis}
\end{tikzpicture}


\end{document}

My solution Illustration of problems

share|improve this question
add comment

1 Answer

up vote 5 down vote accepted

Here is a custom hack which is tailored only to the problem at hand. First we redefine the nodes near coords* for our own purposes and removing many of the necessary checks. Because we are sure that we won't be using them. You have to take it inside the TikZ picture environment to make this local to the picture otherwise all pictures will be affected.

Then, when placing the nodes near coords we fix the bounding box of the local scope with a coordinate, named (O) here. Then we reset the transformation inside that scope locally. This allows us to compute the distance to the right y-axis and we west anchor the node with a little shift to the left.

Regarding the first question you can use visualization depends on= key to harvest data from other tables, format the number printing etc.

There might be an easier way to do the positioning but I just made it on auto pilot. Please use this to show smarter ways of doing it.

Here is the full code:

\documentclass{article}
\usepackage{pgfplots}
\usepackage{filecontents}
\pgfplotsset{compat=1.7}
\usetikzlibrary{calc}

\begin{filecontents}{data1.dat}
Age-interval  Y-Position  Score   Name  
20-30         1           0.15    Peter
30-40         2           0.20    Jeff  
40-50         3           0.12    Steve
50-60         4           1.24    John  
\end{filecontents}
\begin{filecontents}{data2.dat}
Age-interval  Y-Position  Score    Name    
20-30         1           0.159    Peeteer 
30-40         2           0.209    Jeeff   
40-50         3           0.129    Steevee 
50-60         4           1.249    Joohn   
\end{filecontents}

\pgfkeys{/pgfplots/nodes near coords*/.append style={scatter/@post marker code/.code={%
       \begin{scope}
         \coordinate (O) at (0,0);
         \pgftransformreset
         \path let \p1 = ($(axis description cs:1,1)-(O)$) in
          node[/pgfplots/every node near coord,anchor=west] at ([xshift=\x1+1.5mm]O) {#1};
       \end{scope}
       }
    }
}

\begin{document}
\begin{tikzpicture}
\begin{axis}[
    xbar,clip=false,     
    ytick=data,
    width=8 cm,height=6 cm,
    enlarge y limits={true, value=0.2},
    xmin=-0.01,xmax = 2.0,
    xticklabel pos = upper,
    tick align = outside,
    yticklabel pos=left, 
    yticklabels from table={data2.dat}{Age-interval},
    visualization depends on={value \thisrow{Name} \as \labela},
    visualization depends on={value \thisrow{Score} \as \labelb},
    every node near coord/.append style={
      font=\small,
    },
    nodes near coords={\pgfmathprintnumber[sci]{\labelb} (\labela)},
]
\addplot table [
    y=Y-Position,
    x=Score,
] {data1.dat};
\addplot table [
    y=Y-Position,
    x=Score,
] {data2.dat};
\end{axis}
\end{tikzpicture}
\end{document}

enter image description here

share|improve this answer
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.