[Tex/LaTex] Primary, secondary and tertiary ticks

tickstikz-pgf

What options exist for adding 3 (or more) different types of ticks to a graph axis? An example of this formatting would be something like what you see on a standard ruler, where you have the major tick (cm) marked with a long line and a number, the minor tick marked with a short line only (mm), and a second type of minor tick marking the half way point between major ticks, which is longer than the minor tick, but shorter than the major one.

ruler

edit Here's an ad hoc solution that works only for simple cases, but will be a coding nightmare for anything even slightly more complex. It's also incapable of more than 3 types of ticks.

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

\begin{tikzpicture}
\begin{axis}
[xmin=0,xmax=10,
xtick distance=1,
minor x tick num=9,
extra x ticks ={0.5,1.5,2.5,3.5,4.5,5.5,6.5,7.5,8.5,9.5},
extra x tick style={major tick length=0.15cm, xticklabels={}},
major tick length=0.2cm,
]
\addplot coordinates {(0,0)};
\end{axis}
\end{tikzpicture}

\end{document}

Ideally a general solution will not need to explicitly list every tertiary tick mark, e.g something like:

xtick distance=1, % major tick every 1 inch
minor(type 1) x tick num=1, % minor tick every 1/2 inch
minor(type 2) x tick num=3, % minor tick every 1/4 inch
minor(type 3) x tick num=7, % minor tick every 1/8 inch
minor(type 4) x tick num=15, % minor tick every 1/16 inch

Best Answer

Using dummy axis environment

You can set up exactly the same axis environments and ask them to draw different minor ticks for you.

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

\begin{tikzpicture}
    % top for inch
    \begin{axis}[
        ytick=\empty,
        axis x line=top,
        x axis line style={-},
        xticklabel={\pgfmathparse{int(\tick/2.54)}$\pgfmathresult$ in},
        xmin=0,xmax=10,
        xtick distance=2.54,
        major tick length=20,
    ]
        \addplot coordinates {(0,0)};
    \end{axis}
    % top for 1/2 inch
    \begin{axis}[
        axis y line=none,
        ytick=\empty,
        axis x line=top,
        x axis line style={draw=none},
        xticklabels={},
        xmin=0,xmax=10,
        xtick distance=2.54,
        major tick length=0,
        minor x tick num=1,
        minor tick length=15,
    ]
        \addplot coordinates {(0,0)};
    \end{axis}
    % top for 1/4 inch
    \begin{axis}[
        axis y line=none,
        ytick=\empty,
        axis x line=top,
        x axis line style={draw=none},
        xticklabels={},
        xmin=0,xmax=10,
        xtick distance=2.54,
        major tick length=0,
        minor x tick num=3,
        minor tick length=10,
    ]
        \addplot coordinates {(0,0)};
    \end{axis}
    % top for 1/8 inch
    \begin{axis}[
        axis y line=none,
        ytick=\empty,
        axis x line=top,
        x axis line style={draw=none},
        xticklabels={},
        xmin=0,xmax=10,
        xtick distance=2.54,
        major tick length=0,
        minor x tick num=7,
        minor tick length=5,
    ]
        \addplot coordinates {(0,0)};
    \end{axis}
    % middle for 50pt
    \begin{axis}[
        ytick=\empty,
        axis x line=middle,
        x axis line style={-},
        xticklabel={\pgfmathparse{int(\tick*28.4527559055+.1)}$\pgfmathresult$pt},
        xmin=0,xmax=10,
        xtick distance=1.7572990176,
        major tick length=20,
    ]
        \addplot coordinates {(0,0)};
    \end{axis}
    % middle for 10pt
    \begin{axis}[
        axis y line=none,
        ytick=\empty,
        axis x line=middle,
        x axis line style={draw=none},
        xticklabels={},
        xmin=0,xmax=10,
        xtick distance=1.7572990176,
        major tick length=0,
        minor x tick num=5,
        minor tick length=10,
    ]
        \addplot coordinates {(0,0)};
    \end{axis}
    % bottom for cm
    \begin{axis}[
        ytick=\empty,
        axis x line=bottom,
        x axis line style={-},
        xticklabel={\pgfmathparse{int(\tick)}\small$\pgfmathresult$cm},
        xmin=0,xmax=10,
        xtick distance=1,
        major tick length=20,
    ]
        \addplot coordinates {(0,0)};
    \end{axis}
    % bottom for .5 cm
    \begin{axis}[
        axis y line=none,
        ytick=\empty,
        axis x line=bottom,
        x axis line style={draw=none},
        xticklabels={},
        xmin=0,xmax=10,
        xtick distance=1,
        major tick length=0,
        minor x tick num=1,
        minor tick length=15,
    ]
        \addplot coordinates {(0,0)};
    \end{axis}
    % bottom for .1 cm
    \begin{axis}[
        axis y line=none,
        ytick=\empty,
        axis x line=bottom,
        x axis line style={draw=none},
        xticklabels={},
        xmin=0,xmax=10,
        xtick distance=1,
        major tick length=0,
        minor x tick num=9,
        minor tick length=10,
    ]
        \addplot coordinates {(0,0)};
    \end{axis}
\end{tikzpicture}

\end{document}


In general

This is just a Theory.

Step 1

First you have to prepare the keys such as

/pgfplots/minor x tick num/.initial=0,
/pgfplots/minor x tick num/.belongs to family=/pgfplots/tick,

This step is not so hard. But it is a good chance to figure out what kind of interface do you want. Check pgfplots.code.tex for samples.

Step 2 [optional]

Users are allowed to input explicit positions of minor ticks by the key /pgfplots/minor xtick or y or z. If you want to mimic this, you can find the definition of \pgfplots@init@collect@firstplotastick in pgfplots.code.tex.

There are also miscellaneous keys such as every minor tick.

Step 3 [recommended]

The macro \pgfplots@check@for@minor@ticks checks whether the user wants to draw minor ticks. I suspects that it is just a matter of optimization. I highly recommended that you do the same thing for your minorer ticks.

Step 4

In pgfplotsticks.code.tex it defines \pgfplots@prepare@tick@coordlists@for. This is an all-in-one macro that calculates the positions of ticks as lists. The complete lists of ticks are then stored in

\pgfplots@prepared@tick@positions@minor@x % or y or z
\pgfplots@prepared@tick@positions@major@x % or y or z

You need to rewrite this macro.

At this place, we see why refuses to draw minor ticks for uneven major ticks --- \pgfplots@minor@tick@dist is a global variable; it does not vary for different major ticks.

Step 5 [optional]

There are minor ticks for log-plots... If you want to...

Step 6

Finally we meet \pgfplots@drawticklines@onorientedsurf@. It will draw ticks at the prescribed position.

You need to rewrite this macro.


That is all I can tell. Be sure to answer your own question once you implement it successfully.

Related Question