8

I'm trying to draw a grouped bar plot, but with added dots "on top" to signify outliers in the results.

Currently I have:

    \begin{figure}[]
      \begin{tikzpicture}
        \begin{axis}[
            width  = 1*\textwidth,
            height = 4.5cm,
            major x tick style = transparent,
            ybar=1*\pgflinewidth,
            bar width=13pt,
            symbolic x coords={A,B,C,D},
            xtick = data,
            enlarge x limits=0.25,
            ymax=15,
            ymin=0,
            legend cell align=left,
            legend style={
                    at={(1,1.05)},
                    anchor=south east,
                    column sep=1ex
            }
        ]
            \addplot[style={fill=red,mark=none}]
                coordinates {(A, 4.44) (B,0.1) (C,4.37) (D,4.07)};

            \addplot[style={fill=green,mark=none}]
                coordinates {(A, 0.4) (B,0.8) (C,0.3) (D,0.5)};

            \addplot[style={fill=blue,mark=none}]
                coordinates {(A, 0.2) (B,0) (C,0.9) (D,0.8)};

            \addplot[style={fill=yellow,mark=none}]
                coordinates {(A, 9.59) (B,0.2) (C,8.86) (D,8.62)};

        \draw node[fill,circle,scale=0.5]{} (axis cs:A,7);
        \draw node[fill,circle,scale=0.5]{} (axis cs:B,11);
        \draw node[fill,circle,scale=0.5]{} (axis cs:C,3);
        \draw node[fill,circle,scale=0.5]{} (axis cs:D,12);

        \legend{C1,C2,C3,C4}
      \end{axis}
    \end{tikzpicture}
\end{figure}

This draws the grouped plots etc, but the "dots" always appear at the (0,0) position, ignoring the relative coordinates. See the picture below, where it is close to the "A". Ideally, I'd like to position such a dot above every bar in the graph. How can I properly specify the coordinates?

Above example

2
  • You're using the \node syntax slightly wrong: It's \node [<options>] at (<coordinate>) {<text};, then your circles will be positioned almost correctly. However, they will appear above the letters A, B, etc., not above a particular bar. Do you want to be able to mark particular bars, or whole groups of bars?
    – Jake
    Sep 30, 2013 at 17:39
  • Yes, I'd like to put dots above every bar, but only groups would be an acceptable alternative.
    – KlaasDC
    Oct 1, 2013 at 5:38

2 Answers 2

6

If you want to add individual data points above specific bars, you can use

\draw (axis cs:A,7) node [xshift=-1.5*\pgfkeysvalueof{/pgf/bar width}, fill,circle,scale=0.5]{};

The red bars would use xshift=-1.5*\pgfkeysvalueof{/pgf/bar width}, the green bars xshift=-0.5*\pgfkeysvalueof{/pgf/bar width}, and so on.

\documentclass{article}
\usepackage{pgfplots, pgfplotstable}
\begin{document}
\pgfplotstableread{
Name C1   C2  C3  C4
A    4.44 0.4 0.2 9.59
B    0.10 0.8 0.0 0.2
C    4.37 0.3 0.9 8.86
D    4.07 0.5 0.8 8.62
}\datatable

\begin{figure}[]
\begin{tikzpicture}
        \begin{axis}[
            width  = 1*\textwidth,
            height = 4.5cm,
            major x tick style = transparent,
            ybar=0,
            bar width=13pt,
            symbolic x coords={A,B,C,D},
            xtick = data,
            enlarge x limits=0.25,
            ymax=15,
            ymin=0,
            legend cell align=left,
            legend style={
                    at={(1,1.05)},
                    anchor=south east,
                    column sep=1ex
            }
        ]
            \addplot[style={fill=red,mark=none}]
                coordinates {(A, 4.44) (B,0.1) (C,4.37) (D,4.07)};

            \addplot[style={fill=green,mark=none}]
                coordinates {(A, 0.4) (B,0.8) (C,0.3) (D,0.5)};

            \addplot[style={fill=blue,mark=none}]
                coordinates {(A, 0.2) (B,0) (C,0.9) (D,0.8)};

            \addplot[style={fill=yellow,mark=none}]
                coordinates {(A, 9.59) (B,0.2) (C,8.86) (D,8.62)};
        \legend{C1,C2,C3,C4}
        \draw (axis cs:A,7) node [xshift=-1.5*\pgfkeysvalueof{/pgf/bar width}, fill,circle,scale=0.5]{} ;
        \draw (axis cs:C,1.5) node [xshift=0.5*\pgfkeysvalueof{/pgf/bar width}, fill,circle,scale=0.5]{} ;
      \end{axis}
    \end{tikzpicture}
\end{figure}
\end{document}

If you only want to highlight particular bars, you can use the nodes near coords functionality, which can be used to place nodes near data points. When providing data using \addplot coordinates (as opposed to using a table), you can simply add [\textbullet] after the coordinates you want to highlight. Note that you'll need to also set point meta=explicit symbolic in the axis options, otherwise nodes near coords creates labels containing the y values of the bars.

Compared to "manually" placing TikZ nodes at the desired locations, this has the advantage of using much less code, and being more easily maintainable because you define the marks together with the data, and don't have to type the coordinate values twice.

\documentclass{article}
\usepackage{pgfplots}
\begin{document}

\begin{figure}[]
\begin{tikzpicture}
        \begin{axis}[
            width  = 1*\textwidth,
            height = 4.5cm,
            major x tick style = transparent,
            ybar=1*\pgflinewidth,
            bar width=13pt,
            symbolic x coords={A,B,C,D},
            xtick = data,
            enlarge x limits=0.25,
            ymax=15,
            ymin=0,
            legend cell align=left,
            legend style={
                    at={(1,1.05)},
                    anchor=south east,
                    column sep=1ex
            },
            nodes near coords,
            point meta=explicit symbolic
        ]
            \addplot[style={fill=red,mark=none}]
                coordinates {(A, 4.44)[\textbullet] (B,0.1) (C,4.37) (D,4.07)};

            \addplot[style={fill=green,mark=none}]
                coordinates {(A, 0.4) (B,0.8) (C,0.3)[\textbullet] (D,0.5)};

            \addplot[style={fill=blue,mark=none}]
                coordinates {(A, 0.2) (B,0) (C,0.9) (D,0.8)};

            \addplot[style={fill=yellow,mark=none}]
                coordinates {(A, 9.59) (B,0.2) (C,8.86) (D,8.62) [\textbullet]};
        \legend{C1,C2,C3,C4}
      \end{axis}
    \end{tikzpicture}
\end{figure}
\end{document}
5
  • But, how can you precisely specify the dot's position then? This only replaces the text near the bars, right? I'd like to show the highest "outlier" with the dot.
    – KlaasDC
    Oct 1, 2013 at 6:05
  • @KlaasDC: If you want to place a dot near the yellow "C" bar, you put [\textbullet] after (C,8.86) in the fourth \addplot. Or am I misunderstanding you?
    – Jake
    Oct 1, 2013 at 6:47
  • But then the dot hovers at a fixed position above the C bar, while I'd like to specify the Y-value of the dot. It's function is similar to an error bar.
    – KlaasDC
    Oct 1, 2013 at 6:56
  • @KlaasDC: Aaah, now I understand, you're not trying to "highlight" a particular plot, you're trying to add new data points
    – Jake
    Oct 1, 2013 at 6:56
  • @KlaasDC: I've edited my answer to show how you can add nodes like data points.
    – Jake
    Oct 1, 2013 at 8:33
2

I'm not sure I understand where it is you want circles exactly, but I'll offer this solution to get the conversation started, since there are no other takers.

This doesn't use tikz and I'm sure a tikz solution is what you would prefer, but in its absence, the \stackinset macro overlays an inset (text or graphics) on an object (text or graphics). I overlaid a few bullets in a fashion I thought might satisfy your need, but please clarify if I missed it. I had to add % to blank lines, since \stackinset is not a long command.

Multiple insets are achieved via nesting, as I show in the MWE. The downside is that you must specify paper (rather than graph) coordinates for the inset location. By using the {c} and {b} arguments, the center-bottom of the inset coordinates are calculated relative to the center-bottom of the image.

\documentclass{article}
\usepackage{tikz}
\usepackage{pgfplots}
\usepackage{stackengine}[2013-09-11]
\begin{document}
    \begin{figure}[]
     \stackinset{c}{-3.92cm}{b}{1.52cm}{$\bullet$}{%
     \stackinset{c}{1.22cm}{b}{0.72cm}{$\bullet$}{%
      \begin{tikzpicture}
        \begin{axis}[
            width  = 1*\textwidth,
            height = 4.5cm,
            major x tick style = transparent,
            ybar=1*\pgflinewidth,
            bar width=13pt,
            symbolic x coords={A,B,C,D},
            xtick = data,
            enlarge x limits=0.25,
            ymax=15,
            ymin=0,
            legend cell align=left,
            legend style={
                    at={(1,1.05)},
                    anchor=south east,
                    column sep=1ex
            }
        ]
            \addplot[style={fill=red,mark=none}]
                coordinates {(A, 4.44) (B,0.1) (C,4.37) (D,4.07)};
%
            \addplot[style={fill=green,mark=none}]
                coordinates {(A, 0.4) (B,0.8) (C,0.3) (D,0.5)};
%
            \addplot[style={fill=blue,mark=none}]
                coordinates {(A, 0.2) (B,0) (C,0.9) (D,0.8)};
%
            \addplot[style={fill=yellow,mark=none}]
                coordinates {(A, 9.59) (B,0.2) (C,8.86) (D,8.62)};
%
%        \draw node[fill,circle,scale=0.5]{} (axis cs:A,7);
%        \draw node[fill,circle,scale=0.5]{} (axis cs:B,11);
%        \draw node[fill,circle,scale=0.5]{} (axis cs:C,3);
%        \draw node[fill,circle,scale=0.5]{} (axis cs:D,12);
%
        \legend{C1,C2,C3,C4}
      \end{axis}
    \end{tikzpicture}%
   }}
  \end{figure}
\end{document}

enter image description here

2
  • That looks exactly how I want it! :) There is really no way to use the graph's coordinates though? For example, could it not be possible to draw a second set of "invisible" bars on top of the original ones, but with dot markers at the values?
    – KlaasDC
    Oct 1, 2013 at 5:41
  • @KlaasDC I am not a tikz guy, so I'll have to let someone else solve that one. But since no one had contributed a tikz answer, I provided this as a last resort. Oct 1, 2013 at 10:05

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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