3
$\begingroup$

Let me start by saying there are a lot of other questions here on SE and elsewhere about tick marks in MMA but I think I am correct in saying that none of them cover exactly what I want (apologies if I am wrong!).

The Goal:

The crux of my problem is that I want control over the placement of tick mark labels - the ability to offset the label in some way from the tick mark itself.

My goal is to be able to produce plots with ticks like the following:

enter image description here

I understand that this is a little contrived in that one is unlikely to have such tick marks but alas it details my problem. I have two issues with this plot:

  1. The long tick marks are touching their corresponding labels.
  2. The code to create it is verbose and involves creating two plots and combining them via Overlay.

The Problem:

If I attempt to create staggered ticks as in the above plot in one go then all the tick labels are placed at the same vertical position, irrespective of their own tick mark length:

    Plot[x/1000, {x, 0, 1000}, Frame -> True, FrameTicks ->
      {{Automatic,Automatic},{
        Join[
          LinTicks[0, 1000, 200, 10, TickDirection -> Out, TickLengthScale -> 1],
          LinTicks[100, 1000, 200, 1, TickDirection -> Out, TickLengthScale -> 6]
        ],
      Automatic}}
    ]

enter image description here

The function LinTicks is from the very good CustomTicks package, part of SciDraw, formerly LevelScheme. It simply automates the process of creating a List of well formatted Tick mark descriptions, for example the first LinTicks function there creates a List starting:

    {{0., "   0", {0, 0.01}, {}}, {200., " 200", {0, 0.01}, {}}, ...

For those without LinTicks the full List of Tick mark specifications is included lower down.

The unsatisfactory formatting of the tick labels is therefore not an aspect of the package but rather MMA itself. I understand that in many cases one would want all the tick labels aligned but I cannot find a way to alter this. If there were an option I would be able to:

  1. Move some tick labels down so they are not touching their tick mark, this appears to be a shortfall on MMA's behalf.
  2. Move the other tick labels up, closer to their shorter tick marks and thus avoid having to resort to Overlay to create the first plot.

Any ideas guys? How does MMA decide were to put the labels? Best way to get manual control over this? Cheers!

List of Ticks

    {{0., "   0", {0, 0.01}, {}}, {200., " 200", {0, 0.01}, {}},{400., " 400", {0, 0.01}, {}}, {600., " 600", {0, 0.01}, {}}, {800., " 800", {0, 0.01}, {}}, {1000., "1000", {0, 0.01}, {}}, {20.,"", {0, 0.005}, {}}, {40., "", {0, 0.005}, {}}, {60., "", {0, 0.005}, {}}, {80.,"", {0, 0.005}, {}}, {100., "", {0, 0.005}, {}}, {120., "", {0, 0.005}, {}}, {140., "", {0, 0.005}, {}}, {160., "", {0, 0.005}, {}}, {180., "", {0, 0.005}, {}}, {220., "", {0, 0.005}, {}}, {240., "", {0, 0.005}, {}}, {260., "", {0, 0.005}, {}}, {280., "", {0, 0.005}, {}}, {300., "", {0, 0.005}, {}}, {320., "", {0, 0.005}, {}}, {340., "", {0, 0.005}, {}}, {360., "", {0, 0.005}, {}}, {380., "", {0, 0.005}, {}}, {420., "", {0, 0.005}, {}}, {440., "", {0, 0.005}, {}}, {460., "", {0, 0.005}, {}}, {480., "", {0, 0.005}, {}}, {500., "", {0, 0.005}, {}}, {520., "", {0, 0.005}, {}}, {540., "", {0, 0.005}, {}}, {560., "", {0, 0.005}, {}}, {580., "", {0, 0.005}, {}}, {620., "", {0, 0.005}, {}}, {640., "", {0, 0.005}, {}}, {660., "", {0, 0.005}, {}}, {680., "", {0, 0.005}, {}}, {700., "", {0, 0.005}, {}}, {720., "", {0, 0.005}, {}}, {740., "", {0, 0.005}, {}}, {760., "", {0, 0.005}, {}}, {780., "", {0, 0.005}, {}}, {820., "", {0, 0.005}, {}}, {840., "", {0, 0.005}, {}}, {860., "", {0, 0.005}, {}}, {880., "", {0, 0.005}, {}}, {900., "", {0, 0.005}, {}}, {920., "", {0, 0.005}, {}}, {940., "", {0, 0.005}, {}}, {960., "", {0, 0.005}, {}}, {980., "", {0, 0.005}, {}}, {100., "100", {0, 0.06}, {}}, {300., "300", {0, 0.06}, {}}, {500., "500", {0, 0.06}, {}}, {700., "700", {0, 0.06}, {}}, {900., "900", {0, 0.06}, {}}}

Failed Solutions:

As I said at the beginning, there are many other questions about tick marks but I have been unable to adapt their solutions to my needs.

One common solution for tweaking tick label positions is to wrap the label inside a Frame or Panel environment (here and here) and then try to squeeze it up or down inside but I find this only provides a little wiggle room.

For completeness here is the current code to implement the first plot (it would be desirable to avoid having to make two plots):

    f[x_] := Piecewise[{{1 - Exp[-x/150], x > 0}}]

    {xmin, xmax} = {-30, 1000};
    {ymin, ymax} = {0, 1.05};

    With[{
      opts = Sequence[
        Frame -> True,
        PlotRangePadding -> None,
        Axes -> False,
        ImageSize -> 400,
        ImagePadding -> {{40, 10}, {40, 30}}
        ]
      },

     p1 = Plot[f[x], {x, xmin, xmax},
       opts,
       FrameLabel -> {{"y", None}, {"x", None}},
       FrameTicks -> {
         {
          LinTicks[0, 1, 0.2, 5],
          LinTicks[0, 1, 0.2, 5, ShowTickLabels -> False]
          }, {
          LinTicks[0, xmax, 200, 10, TickDirection -> Out, 
           TickLengthScale -> 1],
          LinTicks[0, xmax, 200, 10, ShowTickLabels -> False]
          }
         }
       ];

     p2 = Plot[f[x], {x, xmin, xmax},
       opts,
       PlotStyle -> None,
       FrameTicks -> {{None, None},
         {
          LinTicks[100, xmax, 200, 1, TickDirection -> Out, 
           TickLengthScale -> 6],
          LinTicks[100, xmax, 200, 1, ShowTickLabels -> False]
          }
         }        
       ];

     o = Overlay[{p1, p2}]
     ]
$\endgroup$
2
$\begingroup$
ticks =
  Join[
   Transpose[{#, Column[{"", PaddedForm[#, {5, 2}]}] & /@ #, 
       Array[{0., 0.06} &, Length@#]}] &[Range[100, 900, 200]],
   Transpose[{#, PaddedForm[#, {5, 2}] & /@ #, 
       Array[{0, 0.02} &, Length@#]}] &[Range[0, 1000, 200]]];

Plot[x/1000, {x, 0, 1000},
 FrameLabel -> {x, y},
 Frame -> True,
 FrameTicks -> {{All, None}, {ticks, None}},
 GridLines -> {Range[100, 900, 200], Automatic},
 GridLinesStyle -> Directive[Gray, Dotted],
 ImageSize -> Large]

enter image description here

$\endgroup$
  • $\begingroup$ You can stop the ticks from extending into the plot area by replacing your 0.1 and 0.02 inside the Array's with {0, 0.05} and {0, 0.01} respectively. Using a Column on the longer tick mark labels to prevent the clipping is good, but this is still only a partial solution, requiring more of a hack than I'd like (with the column) and still an Overlay to deal with more than one vertical position. Still interesting though, thanks. $\endgroup$ – Quantum_Oli Dec 1 '15 at 18:23

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.