Take the 2-minute tour ×
Mathematica Stack Exchange is a question and answer site for users of Mathematica. It's 100% free, no registration required.

What's the best (most elegant, shortest, easiest to read) way to add minor grid lines to a plot?

Here is an example:

data = Table[{x, Log@x}, {x, 100}];
ListPlot[data, Frame -> True, GridLines -> Automatic]

what I get

But this gives gridlines only at the position of the major frameticks. I'm looking for an easy way to automatically generate minor grid lines at the positions of minor frameticks (in a style different from the major gridlines).

Here is an example (yes, made in excel)

What I would like to get

I guess I could write half a page of code to generate both the frame ticks and the gridlines, but it seems like an overkill.

I realize this is very similar to this question, but if I have to enter the ranges manually for each plot then I might as well draw my plots in excel.

share|improve this question
    
Maybe could use similar methods in this question. –  Silvia Apr 26 '13 at 8:43
add comment

4 Answers 4

This is what came to my mind

myGridDivision[{min_, max_}, {major_, majorStyle_}, {minor_, minorStyle_}] :=
 Function[divisions,
   Join[{#, majorStyle} & /@ divisions[[1]],
    {#, minorStyle} & /@ Complement[Flatten[#[[2]]], #[[1]]] &@ divisions]
   ][FindDivisions[{min, max}, {major, minor}]]

ListPlot[data, Frame -> True,
 FrameTicks -> {{True, False}, {True, False}},
 PlotRange -> {{0, 100}, {0, 5}},
 GridLines -> {
   myGridDivision[{0, 100}, {5, GrayLevel[.5]}, {5, GrayLevel[.8]}],
   myGridDivision[{0, 5}, {5, GrayLevel[.5]}, {5, GrayLevel[.8]}]
   }]

enter image description here

You can always set min/max to far more negative/positive large than the actual range of the plot to avoid manully determine the range.

Unfortunately, for some custom set FrameTicks cases, it seems not possible to auto-determine the FrameTicks setting using AbsoluteOptions[(*graphics*), FrameTicks] after the plot has been generated.. Maybe a home-made frame-ticks generator along with this one would be good.

share|improve this answer
add comment

Not elegant, but at least it's quite short :)

makeGrid[{minX_, maxX_}, {minY_, MaxY_}, {xStep_, yStep_}] := 
 {AbsoluteThickness[.25],
   Table[{If[Mod[x, 10] == 0, Black, LightGray], 
     Line[{{x , -100}, {x , 100}}]}, {x, minX, maxX, xStep}],
   Table[{If[Mod[y, 1] == 0, Black, LightGray], 
     Line[{{-100, y}, {100, y}}]}, {y, minY, MaxY, yStep}]}

ListPlot[data, Frame -> True, 
 Prolog -> makeGrid[{0, 100}, {0, 10}, {10, .1}]]

rules

share|improve this answer
    
+1 for Prolog. Had a similar one. :) –  Silvia Apr 26 '13 at 10:16
    
@Silvia so that's where I'd seen it before! :) Still, good practice to code these things up without looking sometimes... –  cormullion Apr 26 '13 at 10:26
    
Good practice indeed :) –  Silvia Apr 26 '13 at 10:35
add comment

I think it is quite useful since it is automatically applicaple:

data = Table[{x, Log@x}, {x, 100}];
plot = ListPlot[data, Frame -> True, GridLines -> Automatic]
{leftTicks, bottomTicks} = 
AbsoluteOptions[plot, FrameTicks][[ 1, 2, {2, 1}]];

we are taking FrameTicks from automatic plot, then we are taking labeled ticks as thicker GridLines and rest as thinner:

horizontalGridLines = 
leftTicks /. {x_?NumericQ, y_String, z__} :> {x, 
 GrayLevel@.9} /. {x_?NumericQ, y_?NumericQ, z__} :> {x, Black}

verticalGridLines = 
bottomTicks /. {x_?NumericQ, y_String, z__} :> {x, 
 GrayLevel@.9} /. {x_?NumericQ, y_?NumericQ, z__} :> {x, Black}

ListPlot[data, Frame -> True, 
GridLines -> {verticalGridLines, horizontalGridLines}]
share|improve this answer
    
AbsoluteOptions[plot, FrameTicks] won't work for some kinds of custom setting FrameTicks, say FrameTicks -> {{True, False}, {True, False}}. –  Silvia Apr 26 '13 at 9:17
    
So do not set it for first plot. It is only to get values we need. But I agree that exact values of FrameTicks given by user in final plot may not match those GridLines in general case. –  Kuba Apr 26 '13 at 9:19
    
Good call! (+1) –  Silvia Apr 26 '13 at 9:22
add comment

Using elements from Kuba's great answer this is what I came up with:

addMajorMinorGridLines[plot_, majorStyle_, minorStyle_] := 
 Block[{leftTicks, bottomTicks, horizontalGridLines, 
   verticalGridLines},
  {leftTicks, bottomTicks} = AbsoluteOptions[plot, FrameTicks][[1, 2, {2, 1}]];
  horizontalGridLines = 
   leftTicks /. {x_?NumericQ, y_String, z__} :> {x, minorStyle} 
            /. {x_?NumericQ, y_?NumericQ, z__} :> {x, majorStyle};

  verticalGridLines = 
   bottomTicks /. {x_?NumericQ, y_String, z__} :> {x, minorStyle} 
               /. {x_?NumericQ, y_?NumericQ, z__} :> {x, majorStyle};
  Show[plot, GridLines -> {verticalGridLines, horizontalGridLines}]
  ]


plot = ListPlot[data, Frame -> True, GridLines -> Automatic, PlotStyle -> Red];
addMajorMinorGridLines[plot, Directive[Thick, Black], Directive[Thin, Opacity@0.3]]

enter image description here

share|improve this answer
    
How will you deal with plot with non-integer ticks, say plot = ListPlot[data, Frame -> True, FrameTicks -> {{{-1, 0, 1}, None}, {{0, Pi, 2 Pi, 3 Pi}, None}}]? –  Silvia Apr 26 '13 at 10:11
    
I tried upvoting this but stackexchange temporarily lost the plot –  cormullion Apr 26 '13 at 10:31
    
@Silvia Good point. I guess "Not now" is not a good answer? I welcome any suggestions. –  Ajasja Apr 26 '13 at 12:30
    
@Ajasja I would say re-constructing a ListGridPlot from Graphics and primitives. :) –  Silvia Apr 26 '13 at 12:59
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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