73

Is there an easy way to 'break' the axis in a pgfplots environment? What I'm talking about is something like this

enter image description here

Any minimal plot will do as an example...for example

\documentclass{minimal}  
\usepackage{tikz}
\usepackage{pgfplots}

\begin{document}
\begin{tikzpicture}
\begin{axis}[ymin=0, ymax=80]
\addplot {x*0}; 
\addplot {x^2+50};
\end{axis}
\end{tikzpicture}

\end{document}

For example, in the below plot,

plot

I want to break the axis from around y = 10 to y = 40.

Any ideas? Does PGF have this functionality? A search for `break' in the manual doesn't yield anything.

6
  • 2
    You can search for axis y discontinuity in the pgfplots manual.
    – percusse
    Mar 1, 2012 at 23:03
  • 2
    The axis y discontinuity option won't let you plot values near the origin, it is only meant for showing that a plot doesn't start near zero. TSGM, could you provide a more concrete example of what you want to achieve? A break in a column plot is much easier than in a line plot.
    – Jake
    Mar 1, 2012 at 23:10
  • @Jake: I've edited the original post to be more specific for what kind of break I want to achieve.
    – TSGM
    Mar 1, 2012 at 23:19
  • I've posted a related question here
    – Enlico
    Dec 18, 2015 at 10:58
  • 2
    I've created a feature request ticket on sourceforge sourceforge.net/p/pgfplots/feature-requests/81
    – Dilawar
    Jul 10, 2018 at 4:34

3 Answers 3

61

One solution for the posted minimal example could be the following:

\documentclass{minimal}  
\usepackage{tikz}
\usepackage{pgfplots}
\usetikzlibrary{pgfplots.groupplots}

\begin{document}
\pgfplotsset{
% override style for non-boxed plots
    % which is the case for both sub-plots
    every non boxed x axis/.style={} 
}
\begin{tikzpicture}
\begin{groupplot}[
    group style={
        group name=my fancy plots,
        group size=1 by 2,
        xticklabels at=edge bottom,
        vertical sep=0pt
    },
    width=8.5cm,
    xmin=-6, xmax=6
]

\nextgroupplot[ymin=45,ymax=80,
               ytick={60,80},
               axis x line=top, 
               axis y discontinuity=parallel,
               height=4.5cm]
\addplot {x*0};     
\addplot {x^2+50};         

\nextgroupplot[ymin=0,ymax=5,
               ytick={0},
               axis x line=bottom,
               height=2.0cm]
\addplot {x*0}; 
\addplot {x^2+50};                 
\end{groupplot}
\end{tikzpicture}

\end{document}

It combines two plots in a groupplot-environment and plots them on top of each other. Using the axis y discontinuity is possible then:

Two plots using axis y discontinuity for the upper.

3
  • Ah yes, that's very clever! Would you mind adding a sentence or two describing the approach?
    – Jake
    Jul 9, 2012 at 22:58
  • 1
    The basic idea is to disable the "boxed" style when gluing two group plots together while setting vertical sep to 0. Then you can define individual axis x line for the upper and lower plot which results in the whole groupplot appearing as one box.
    – der Michi
    Jul 11, 2012 at 10:15
  • I have 3 levels of plots with grids. To hide x-axes in the plot interior, the middle one must have a combination of commands: x axis line style={draw opacity=0}, axis x line*=none.
    – forrest
    Apr 19, 2020 at 8:53
20

Is there an easy way ...

The only "easy" ways to accomplish axis discontinuities are the axis y discontinuity feature mentioned by percusse - which is unavailable for your specific use-case.

Your use-case would need a much more sophisticated implementation which

  • maps coordinates
  • draws discontinuity markers at the correct places into the axis
  • knows how to draw such markers into each bar (and knows how to draw it for other plot handlers as well).

In short: the feature is unavailable. You can post a feature request on sourceforge.

If you are a power-user, you could consider implementing the first two steps using a custom coordinate transformation and some decoration for the axis.

6
  • 4
    Follow up, is there any guru who can solve this problem?
    – user14024
    Apr 28, 2012 at 1:29
  • Plus one with Nadim's request
    – Rave
    May 28, 2012 at 16:08
  • I also need to accomplish something like this. My use case is nearly identical to the excel image in the OP.
    – Trevor
    Aug 20, 2012 at 23:14
  • 5
    Nice feature request. I would need it myself.
    – Pygmalion
    Aug 27, 2012 at 15:28
  • 4
    @christian I was wondering if this capability has been added since this question was asked a long time ago? Thanks.
    – Ali
    Jan 21, 2020 at 3:45
0

I needed discontinuity and interrupting some bars, and if you are fine with not having the decoration on the bar, but simply the bar disappearing, you can work that out with existing functionalities:

ybar plot with discontinuity

It's the same idea as the accepted answer, plus clipping for emphasizing the interruption of the bars. To obtain the "wavy breakpoint" in the bar, you could try to clip with a different path. However, you would have to draw that manually. Some gotchas:

  1. The scale of the y axis is skewed between the two plots. There is no reason why they should have the same scale or unit, so if that is important, you would need to fiddle with ymin and ymax, as well as width and height at least to have pgfplots give you the same tick distance in plot units.
  2. The plotting is duplicated and clipped, but it looks like the plot on top enlarges the bounding box of the tikzpicture, so you might want to plot mutually exclusive sets of data.

Code:

\documentclass{standalone}
\usepackage{pgfplots}
\usepackage{pgfplotstable}

\pgfplotsset{compat=1.9}
\usetikzlibrary{pgfplots.groupplots}


% This data is a precalculated histogram with very uneven bins,
% so we simply use ybar with symbolic coordinates
\pgfplotstableread{
bin_ub     alg1      alg2    alg3
b1p0       210169    210463  207187
b1p01      7577      7603    10867
b1p02      1434      1337    1421
b1p05      2828      2815    2765
b1p1       2724      2747    2747
b1p5       5914      5772    6106
b2p0       1189      1251    1532
binf       2862      2709    2072
}\mytable

\begin{document}
  \begin{tikzpicture}
    \begin{groupplot}[
        group style={
            group size=1 by 2,
            % The two plots will touch one another vertically
            vertical sep=0pt
        },
        % Common settings
        ybar,
        symbolic x coords={b1p0, b1p01, b1p02, b1p05, b1p1, b1p5, b2p0, binf},
        % Make sure all plots span all the symbolic x coordinates, plus the extra enlarged space
        xmin=b1p0,
        xmax=binf,
        enlarge x limits=true,
        % Disable scaling ticks, otherwise we get e.g. x10^4 from the lower plot overlapping with bars
        scaled ticks=false,
      ]

      % Plot above: truncated at the bottom, only shows the top part of the graph
      \nextgroupplot[
          bar width=4pt,
          % This plot will place the legend too
          legend pos=north east,
          legend cell align=left,
          % And as well the y axis label, which is placed at the vertical "0" of this
          % plot, corresponding to the area in the middle of the two
          ylabel style={at={(-0.2, 0.0)}},
          ylabel={instance count},
          % Hide the bottom x line and add the discontinuity symbol
          xtick=\empty,
          axis x line*=top,
          axis y discontinuity=parallel,
          % Set the display range to only the top part of the interesting values
          ymin=1.5e5,
          ymax=2.2e5,
          enlarge y limits=true
        ]

      % Now use clipping to hide portion of the bars to indicate that there is an interruption
      \begin{scope}
        % We need to clip around the bars, but we want to have a little bit of extra space around it.
        % Since the x axis is symbolic, we would need something like $(binf, 0.0)+(15pt, 0)$.
        % We can do that by writing the coordinate as `{[normalized]<NUM>}` which is the way
        % to tell pgfplots that we have already done the conversion into numeric coords.

        % Clip slightly around the interesting area
        \clip
          (axis cs: {[normalized]-1}, 1.5e5)
            rectangle
          (axis cs: {[normalized] 8},  2.2e5);

        % Add all the plots
        % TODO Adding the full plot will enlarge the bounding box of the figure, for some reason.
        % Possible workarounds: filter the table, or manually write only the interesting coordinates.

        \addplot table[x=bin_ub, y=alg1] {\mytable};
        \addlegendentry{Algorithm 1}

        \addplot table[x=bin_ub, y=alg2] {\mytable};
        \addlegendentry{Algorithm 2}

        \addplot table[x=bin_ub, y=alg3] {\mytable};
        \addlegendentry{Algorithm 3}
      \end{scope}

      % Next plot: it will have most of the data
      \nextgroupplot[
          bar width=4pt,
          % This will provide the x axis label, and all the ticks
          xlabel={\% away from optimum},
          xticklabels={$0\%$, $1\%$, $2\%$, $5\%$, $10\%$, $50\%$, $100\%$, $>\!\!100\%$},
          xticklabel style={font=\scriptsize},
          % Force display of all ticks used in data:
          xtick=data,
          % Set the interesting y range so that the long bars are clipped
          ymin=0,
          ymax=1.2e4,
          enlarge y limits=true,
          % Hide the top axis line
          axis x line*=bottom
        ]

      % Same plotting code
      \addplot table[x=bin_ub, y=alg1] {\mytable};
      \addplot table[x=bin_ub, y=alg2] {\mytable};
      \addplot table[x=bin_ub, y=alg3] {\mytable};

    \end{groupplot}
  \end{tikzpicture}
\end{document}

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.