13
$\begingroup$

By default, FrameTicks stick into the data area in a way that is sometimes uncomfortable.

Plot[Cos[x], {x, 0, 10}, Frame -> True]

enter image description here

I see that I can create "outie" ticks manually using

Plot[
 Cos[x], {x, 0, 10}, Frame -> True,
  FrameTicks -> {{{0, 0, {0, 0.01}}, {Pi, Pi, {0, .01}}, {2 Pi, 2 Pi, {0, 0.01}}, {3 Pi, 3 Pi, {0, 0.01}}}, {{-1/2, -1/2, {0, 0.01}}, {1/2, 1/2, {0, 0.01}}}, None, None}
]

enter image description here

But I want to use the automatic tick positions, sizes and labels. I can (kind of) achieve this so:

With[
 {originalPlot = Plot[Cos[x], {x, 0, 10}, Frame -> True]},
 Show[originalPlot, 
  FrameTicks -> AbsoluteOptions[originalPlot, FrameTicks][[1, 2]] /. {a_, b_, {c_, d_}, e___} :> {a, b, {d, c}, e}]
 ]

enter image description here

There are (at least) three problems with this approach:

  1. Extra vertical-axis tick labels have been inserted; all vertical-axis ticks appear to have been converted to minor ticks.

  2. Trailing decimal points have been added to the integer tick labels.

  3. FrameStyle no longer affects the ticks, apparently because the ReplaceAll solution hardcodes the FrameTicks style before FrameStyle is applied:

An example of correct application of FrameStyle (with default, "innie" ticks):

Plot[Cos[x], {x, 0, 10}, Frame -> True, FrameStyle -> Gray]

enter image description here

An example of broken application of FrameStyle:

With[
 {originalPlot = Plot[Cos[x], {x, 0, 10}, Frame -> True, FrameStyle -> Gray]},
 Show[originalPlot, 
  FrameTicks -> AbsoluteOptions[originalPlot, FrameTicks][[1, 2]] /. {a_, b_, {c_, d_}, e___} :> {a, b, {d, c}, e}]
]

enter image description here

How can this approach be improved to address these problems?

$\endgroup$
5
  • $\begingroup$ Unfortunately once you start customizing ticks, you lose most things that automatic ticks provide. What I usually do is use the CustomTicks package (part of LevelScheme) which is very customizable and closely mimics the automatic tick generation. $\endgroup$
    – Szabolcs
    Commented Feb 5, 2013 at 22:31
  • $\begingroup$ @Szabolcs I too use LevelScheme sometimes, but it'd be nice to have a native way of doing this. Thanks for the suggestion. $\endgroup$ Commented Feb 5, 2013 at 22:33
  • 1
    $\begingroup$ As I already experienced in this question and @halirutan pointed out to me in chat, there seems to be a bug in AbsoluteOptions that causes the additional ticks. I doubt that there is an easy way to fix this issue. $\endgroup$
    – einbandi
    Commented Feb 5, 2013 at 22:35
  • $\begingroup$ Why don't you just use PlotRangePadding? E.g. Plot[Cos[x], {x, 0, 10}, Frame -> True, PlotRangePadding -> {.3, .1}] $\endgroup$ Commented Feb 6, 2013 at 1:08
  • $\begingroup$ Closely related: mathematica.stackexchange.com/q/2969/121 $\endgroup$
    – Mr.Wizard
    Commented Feb 8, 2013 at 5:57

4 Answers 4

6
$\begingroup$

I wrote a (somewhat buggy) function to do exactly this a while back. It basically takes a plot, finds the ticks, makes them negative length and replots the plot.

outsideTickPlot[plot_] := Module[{ticks, function, newticks},
  ticks = Ticks /. AbsoluteOptions@plot;
  function = {#1, SetPrecision[#2, Infinity], {-1, 1}*#3, #4} &;
  newticks = Apply[function, ticks, {2}];
  Show[plot, Ticks -> newticks]
  ]

and here is an example:

outsideTickPlot[Plot[x^2, {x, 0, 5}]]

Mathematica graphics

$\endgroup$
7
$\begingroup$

The documentation for FrameTicks shows ways to define functions that get passed the minimum and maximum of your data, and then produce the kinds of ticks you require. To get "nice" divisions, use the FindDivisions function. To get "outie" ticks, you need a (small) positive argument in the second element of the pair-list at the end of the list specifying the tick - the 0.005 here.

myticks[min_, max_] := 
 Table[{i, i, {0, 0.005}}, {i, FindDivisions[{min, max}, 10]}]

You can then specify:

Plot[Sin[x], {x , 0 , 4 Pi}, Frame -> True, 
 FrameTicks -> {{Automatic, Automatic}, {myticks[##] &, None}}]

enter image description here

You can be even fancier with a tick function definition like this:

myticks[min_, max_, n_] := 
 Table[{i, 
   Switch[Head[i], Integer, i, Rational, N@i, True, i], {0, 
    0.005}}, {i, FindDivisions[{min, max}, n]}]

This makes sure you don't get fractions as your tick label, while leaving integers alone.

Plot[Sin[x], {x , 0 , 4 Pi}, Frame -> True, 
 FrameTicks -> {{myticks[##, 5] &, myticks[##, 5] &}, {myticks[##] &, None}}]

enter image description here

One thing to watch out for is that "outie" ticks shrink the framed area, the larger you make them, for a given ImageSize. This might matter to you if you are composing your plots in a Grid or something.

$\endgroup$
4
$\begingroup$
ClearAll[tickF]
tickF[t1_: {0., .02}, t2_: {0., .01}] := Replace[Charting`FindTicks[{0, 1}, {0, 1}][##], 
  {{t_?NumericQ, l_?NumericQ} :> {t, l, t1}, {t_, "", _, c___} :> {t, "", t2, c}}, 1] &;

Examples:

Plot[Cos[x], {x, 0, 10}, Frame -> True,  FrameTicks -> (tickF[] {{1, 1}, {1, 1}})]

enter image description here

Plot[Cos[x], {x, 0, 10}, Frame -> True, 
  FrameTicks -> {{tickF[], tickF[{.02, .02}, {.01, .01}]}, 
    {tickF[{.02, .02}, {0, .01}],  tickF[{.02, 0}, {.01, 0}]}}]

enter image description here

$\endgroup$
1
$\begingroup$
s[j_] := Table[{j i, j i, {0, 0.02}}, {i, -100, 100}];p[j_] := Table[{ j i/5, "", {0, 0.01}}, {i, -99, 99}];ticks[j_] := ArrayFlatten[{{s[j]}, {p[j]}}];


Plot[Cos[x], {x, 0, 10},LabelStyle -> {FontSize -> 17, FontFamily -> "Times", Black},Frame -> True,FrameTicks -> {{ticks[0.5], 
None}, {ticks[2], None}}, PlotRange -> {-1, 1}]  

Note that j reprsents the size step on the axes or you can say the size of the main tick.
enter image description here

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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