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.

I am making a bunch of two dimensional plots and I would like to have them arranged in a grid with no space in between them. That is, I want their frames touching each other.

My problem is twofold. First I don't know how to get the plots to have a consistent size. When I try to give the plots the same size via ImageSize, it applies the size to the overall image, including the tick marks and labels. But when I have two different plots, one with tick labels and one without, giving the same value to ImageSize doesn't give the result I'm looking for.

Secondly, I want to get rid of any white space around the images such that when I give Grid the option Spacings ->{0,0} there really is no visible space between the plots.

In the example code I use the CustomTicks package.

(*an example of what I might plot, simple sum of two dimensional \
Lorentzians*)
lzn[x_, w_, g_] := (x - w + I g)^-1;
exampledata2D = 
  Table[Re[lzn[w1, .2, .1] lzn[w2, .3, .2] + 
     lzn[w1, .4, .1] lzn[w2, .8, .1] + 
     lzn[w1, .8, .2] lzn[w2, .4, .2]], {w1, 0, 1, .01}, {w2, 0, 
    1, .01}];
<< "CustomTicks`";  
standardticks = LinTicks[0, 1, .2, 4];
(*I don't want the last tick label for one plot overlapping with the \
first tick label of the plot right next to it.*)
ticks2 = LinTicks[0, 1, .2, 4, ShowLast -> False];
(*Custom plotting function so I don't have to reprint the same \
options over and over *)
plottingfunction[list_, plotopts : OptionsPattern[]] := 
  ListContourPlot[list, 
   Evaluate[FilterRules[{plotopts}, Options[ListContourPlot]]], 
   Contours -> 30, PlotRange -> All, DataRange -> {{0, 1}, {0, 1}}, 
   BaseStyle -> 18, 
   ColorFunction -> (Blend[{Red, Orange, Yellow, Green, Blue, 
        Darker[Blue]}, #] &)];

bottomleft = 
  plottingfunction[exampledata2D, 
   FrameTicks -> {{ticks2, StripTickLabels[standardticks]}, {ticks2, 
      StripTickLabels[standardticks]}}];
bottomright = 
  plottingfunction[exampledata2D, 
   FrameTicks -> {{StripTickLabels[standardticks], 
      StripTickLabels[standardticks]}, {standardticks, 
      StripTickLabels[standardticks]}}];
topleft = 
  plottingfunction[exampledata2D, 
   FrameTicks -> {{ticks2, 
      StripTickLabels[standardticks]}, {StripTickLabels[
       standardticks], StripTickLabels[standardticks]}}];
topright = 
  plottingfunction[exampledata2D, 
   FrameTicks -> {{StripTickLabels[standardticks], 
      StripTickLabels[standardticks]}, {StripTickLabels[
       standardticks], StripTickLabels[standardticks]}}];

Grid[{{topleft, topright}, {bottomleft, bottomright}}, 
 BaseStyle -> ImageSizeMultipliers -> 1, Spacings -> {0, 0}]

enter image description here

share|improve this question
    
I realize this may be a duplicate, but I didn't find the answer when I searched around. –  Jason B Nov 20 '13 at 19:25
1  
You may be interested in grid full of plots. Fix ImageSize, fix AspectRation, focus on FrameTicks, use ImagePadding for plot and Spacing for Grid. –  Kuba Nov 20 '13 at 19:30
    
A good solution might be to use the LevelScheme package which can handle these things. This answer mentions it. –  Szabolcs Nov 20 '13 at 19:34
    
More resources here and here. –  Szabolcs Nov 20 '13 at 19:50
    
@Szabolcs, if you added the disclaimer at the top, could you change it to point to grid full of plots instead of Aligning plot axes in a graphics object as that is the post I used to solve this. Thanks. –  Jason B Nov 20 '13 at 20:33

2 Answers 2

Another way to do this is to use the SciDraw package (LevelScheme successor). (Note: I'm still learning to use this package and I may not be doing things in the most efficient way. Also, the package is still in beta as of November 2013.)

This is the plot we're going to have in the grid:

plot = plottingfunction[exampledata2D];

First, load the package:

<<SciDraw`

A very simple way to construct the grid, exploiting the fact that all nine subplots are identical, is the following:

Figure[
 Multipanel[
  {
   FigurePanel[{FigGraphics[plot]}, All, (* "All" means evaluate this for all subplots *)
     PanelLetterTextColor -> White];
  },

  Dimensions -> {3, 3}  (* a 3 by 3 grid *)
 ],

 CanvasSize -> 8 {1, 1} (* the canvas aspect ratio sets the subplot aspect ratio too *)
]

Of course in practical situations the subplots are all different. Here's a more realistic way to do it which is convenient if the subplots are different but have the same plot range:

DefineStyle["ContourArray",
 {
  FigurePanel -> {
    XPlotRange -> {0, 1}, (* these need to be set if different from {0,1} *)
    YPlotRange -> {0, 1},
    YTickLabelRange -> {0.2, 1},
    XTickLabelRange -> {0.2, 1},
    PanelLetterTextColor -> White }
 }
]

Figure[
 Multipanel[
  {
   FigurePanel[{FigGraphics[plot]}, {1, 1}];
   FigurePanel[{FigGraphics[plot]}, {1, 2}];
   FigurePanel[{FigGraphics[plot]}, {1, 3}];
   FigurePanel[{FigGraphics[plot]}, {2, 1}];
   FigurePanel[{FigGraphics[plot]}, {2, 2}];
   FigurePanel[{FigGraphics[plot]}, {2, 3}];
   FigurePanel[{FigGraphics[plot]}, {3, 1}, XTickLabelRange -> All];
   FigurePanel[{FigGraphics[plot]}, {3, 2}];
   FigurePanel[{FigGraphics[plot]}, {3, 3}];       
  },

  Dimensions -> {3, 3}
 ],

 Style -> "ContourArray",
 CanvasSize -> 8 {1, 1}
]

enter image description here

Note how the tick label overlap was solved: the default tick range was set to $0.2 - 1.0$ and it was overridden on the bottom left panel only.

To disable the automatic panel lettering, use PanelLetter -> None in the style.

share|improve this answer
1  
Wow! SciDraw is the answer to my Mathematica plotting prayers ... I want to go have a cry I am so happy. –  Gabriel Dec 9 '13 at 0:42
    
I notice that the documentation and your example makes the arguments to *Panel's as a list of a single element, using ; to separate the different plotting directives. I find you can just change this to a list (which seems more natural to me). Is there any reason for the ; style or is it just preference? Things like this always suggest my lack of deep MMA knowledge... –  Gabriel Dec 9 '13 at 2:24
1  
To answer my own question ... the use of ; is stylistic and is explained in section 10.1 of the SciDraw documentation. –  Gabriel Dec 9 '13 at 3:32
up vote 5 down vote accepted

Thanks to Kuba and Szabolcs for pointing out many related posts. I recognize that LevelScheme is probably the best way to go here, but at the moment I don't have the time to learn everything I need in order to use it.

I am going to use Jens's solution from this page, but I have to remove the certain tick labels so that they don't overlap each other.

(*an example of what I might plot, simple sum of two dimensional \
Lorentzians*)
lzn[x_, w_, g_] := (x - w + I g)^-1;
exampledata2D = 
  Table[Re[lzn[w1, .2, .1] lzn[w2, .3, .2] + 
     lzn[w1, .4, .1] lzn[w2, .8, .1] + 
     lzn[w1, .8, .2] lzn[w2, .4, .2]], {w1, 0, 1, .01}, {w2, 0, 
    1, .01}];
<< "CustomTicks`";  
tickbottom = LinTicks[-1, 1, .5, 5, ShowLast -> False];
ticktop = LinTicks[-1, 1, .5, 5, ShowFirst -> False];
tickmiddle = 
  LinTicks[-1, 1, .5, 5, ShowFirst -> False, ShowLast -> False];
standardticks = LinTicks[-1, 1, .5, 5];
plottingfunction[list_, horizontalposition_, verticalposition_, 
   plotopts : OptionsPattern[]] := 
  ListContourPlot[list, 
   Evaluate[FilterRules[{plotopts}, Options[ListContourPlot]]], 
   Contours -> 30, DataRange -> {{-1, 1}, {-1, 1}}, BaseStyle -> 18, 
   ColorFunction -> (Blend[{Red, Orange, Yellow, Green, Blue, 
        Darker[Blue]}, #] &), PlotRangePadding -> None, 
   PlotRange -> All, 
   FrameTicks -> {{Which[verticalposition == "Top", ticktop, 
       verticalposition == "Middle", tickmiddle, 
       verticalposition == "Bottom", tickbottom], 
      StripTickLabels[standardticks]}, {If[
       verticalposition == "Bottom", 
       Which[horizontalposition == "Right", ticktop, 
        horizontalposition == "Middle", tickmiddle, 
        horizontalposition == "Left", tickbottom], 
       StripTickLabels[standardticks]], 
      StripTickLabels[standardticks]}}];

Options[plotGrid] = {ImagePadding -> 40};
plotGrid[l_List, w_, h_, opts : OptionsPattern[]] := 
 Module[{nx, ny, sidePadding = OptionValue[plotGrid, ImagePadding], 
   topPadding = 0, widths, heights, dimensions, positions, 
   frameOptions = 
    FilterRules[{opts}, 
     FilterRules[Options[Graphics], 
      Except[{ImagePadding, Frame, FrameTicks}]]]}, {ny, nx} = 
   Dimensions[l];
  widths = (w - 2 sidePadding)/nx Table[1, {nx}];
  widths[[1]] = widths[[1]] + sidePadding;
  widths[[-1]] = widths[[-1]] + sidePadding;
  heights = (h - 2 sidePadding)/ny Table[1, {ny}];
  heights[[1]] = heights[[1]] + sidePadding;
  heights[[-1]] = heights[[-1]] + sidePadding;
  positions = 
   Transpose@
    Partition[
     Tuples[Prepend[Accumulate[Most[#]], 0] & /@ {widths, heights}], 
     ny];
  Graphics[
   Table[Inset[
     Show[l[[ny - j + 1, i]], 
      ImagePadding -> {{If[i == 1, sidePadding, 0], 
         If[i == nx, sidePadding, 0]}, {If[j == 1, sidePadding, 0], 
         If[j == ny, sidePadding, topPadding]}}, AspectRatio -> Full],
      positions[[j, i]], {Left, Bottom}, {widths[[i]], 
      heights[[j]]}], {i, 1, nx}, {j, 1, ny}], 
   PlotRange -> {{0, w}, {0, h}}, ImageSize -> {w, h}, 
   Evaluate@Apply[Sequence, frameOptions]]]

plotGrid[Table[
  plottingfunction[exampledata2D, h, 
   v], {v, {"Top", "Middle", "Bottom"}}, {h, {"Left", "Middle", 
    "Right"}}], 1000, 1000]

enter image description here

I'm not 100% happy with the way it looks, with the missing tick labels, but it is better than having the labels overlap or get cut off.

share|improve this answer
    
I use LevelScheme a lot and I don't suggest using it for this. Your solution is far better/simpler, IMO. LevelScheme works great for line plots, but I've found using 2D plots (images/ArrayPlots/ContourPlots, etc.) to be a royal pain in the ass. I'm not sure what you mean by "missing tick labels" — they all seem to be there. Am I missing something? –  rm -rf Nov 22 '13 at 14:21
1  
@rm-rf, in order that the 1.0 label from one plot not overlap with the -1.0 label from the next, I've omitted them both for the points where the plots meet. I don't think that's the most aesthetically pleasing solution. I'd rather omit one label or the other, but not both. The problem with that is that both labels hang off the side just a bit, so when I trim the plots so they don't have any padding, it cuts off a portion of the label I'm keeping. I think what I'll do now is just add the 1.0 in that spot in Inkscape, since I'm going to be adding plot labels in Inkscape anyways. –  Jason B Nov 22 '13 at 17:15
    
That is a problem I've often faced (and I like making plots like these). My approaches to fix this has been to either label the x/y ticks in detail on the lower left plot and nowhere else (but tick marks still present) or to have a gap between the plots to accommodate the two extra ticks (I usually favour the second approach). Having only one of them would be a tad confusing, especially if the plots are arranged without any gap. –  rm -rf Nov 22 '13 at 18:58
    
This question is closed, but I really wanted to add another solution using the SciDraw package, that I am learning to use now. I added the solution to your answer, just edit it to your liking ... @rm-rf with this package it turned out to be relatively convenient. –  Szabolcs Nov 27 '13 at 17:28
    
@Szabolcs The question is open now. Feel free to post an answer –  rm -rf Nov 27 '13 at 17:46

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.