6
$\begingroup$

I need to add a small graphics on top of a larger one, and the small graphics should stick very close to the large one, with their axis aligned. Here's a minimal code to work with, using some elements from this question/answer :

How to make a plot on top of other plot?

Intensity[p_, q_, phi_] := Plot[
    (If[p > 0, Sin[2Pi p^2 x]/(2Pi p^2 x), 1]Cos[2Pi p^2 q x + phi/2])^2,
    {x, -30, 30},
    PlotPoints -> 400,
    MaxRecursion -> 4,
    PlotRange -> All,
    PlotRange -> {{-30, 30}, {0, 1}},
    Axes -> False,
    AspectRatio -> 1,
    Frame -> True,
    ImageSize -> {600, 600}
]

LumIntensity[p_, q_, phi_] := DensityPlot[
    (If[p > 0, Sin[2Pi p^2 x]/(2Pi p^2 x), 1]Cos[2Pi p^2 q x + phi/2])^2,
    {x, -30, 30}, {y, 0, 1}, 
    AspectRatio -> 0.1,
    PlotPoints -> {1000, 2},
    Frame -> None, 
    ImageSize -> 600
]

GraphicsColumn[
    {LumIntensity[0.25, 5, 0], Intensity[0.25, 5, 0]},
    Spacings -> 0
]

Here's what I want to achieve (which the question/answer above don't solve) :

interference

Also, how can I add a black frame around the small graphics ? Using Frame -> True or Framed[...] gives an ugly output.

The combination would be used for a Manipulate box, since p, q and phi are variables.

EDIT : Actually, it would be better if the small graphics was placed at the bottom of the large one.

$\endgroup$
3
  • 1
    $\begingroup$ Try Frame -> TrueFrameTicks -> None, PlotRange -> Full $\endgroup$
    – chris
    Commented Apr 3, 2016 at 16:20
  • $\begingroup$ @chris, thanks, this works for the frame around the small graphics. $\endgroup$
    – Cham
    Commented Apr 3, 2016 at 16:24
  • $\begingroup$ Using Epilog in the large graphics, and Inset for the small graphics could partially solve my issue. Unfortunately, if I resize the large graphics by hand, the small one isn't well aligned anymore with the marks on the large graphics. $\endgroup$
    – Cham
    Commented Apr 3, 2016 at 16:28

4 Answers 4

9
$\begingroup$

I think it may perhaps be easier just to combine plots and modify (e.g. suppress unnecessary frame ticks). I post this as a motivating answer rather than definitive answer. li is a modified version of OP function:

li[p_, q_, phi_, {l_, u_}] := 
 DensityPlot[(If[p > 0, Sin[2 Pi p^2 x]/(2 Pi p^2 x), 1] Cos[
      2 Pi p^2 q x + phi/2])^2, {x, -30, 30}, {y, l, u}, 
  AspectRatio -> 0.1, PlotPoints -> {1000, 2}, Frame -> None, 
  ImageSize -> 600]
Manipulate[
 Show[Intensity[0.25, 5, 0], li[0.25, 5, 0, {l, u}]], {l, -1, 0, 
  Appearance -> "Labeled"}, {{u, -0.5}, -1, 0, 
  Appearance -> "Labeled"}]

enter image description here

$\endgroup$
3
  • $\begingroup$ Very nice ! Thanks a lot ! $\endgroup$
    – Cham
    Commented Apr 4, 2016 at 12:56
  • $\begingroup$ This solution is simpler and more natural than my Inset + Epilog solution. The code is a bit shorter. I'll adopt it as the solution to the problem. $\endgroup$
    – Cham
    Commented Apr 4, 2016 at 13:22
  • $\begingroup$ @Cham thank you. My aim with Manipulate was to find the desired bounds. I am glad it was helpful. :) $\endgroup$
    – ubpdqn
    Commented Apr 4, 2016 at 13:24
4
$\begingroup$

This is a partial solution, using Epilog and Inset. It has an alignment problem, especially after we resize the picture by hand inside the Manipulate box. Also, without resizing the whole, playing with the parameters may give an alignment problem after a while. How to fix this ?

LumIntensity[x_, p_, q_] := (If[p > 0, Sin[2Pi p^2 x]/(2Pi p^2 x), 1]Cos[2Pi p^2 q x])^2

Intensity1[p_, q_] := Inset[
    DensityPlot[LumIntensity[x, p, q],
    {x, -30, 30}, {y, 0, 1},
    ColorFunction -> GrayLevel,
    AspectRatio -> 0.1,
    Frame -> None,
    PlotPoints -> {1000, 2},
    ImageSize -> 600],
    {0, -0.1}
]

Intensity2[p_, q_] := Plot[
    LumIntensity[x, p, q],
    {x, -30, 30},
    PlotPoints -> 400,
    MaxRecursion -> 4,
    PlotRange -> {{-30, 30}, {-0.2, 1}},
    Axes -> None,
    AspectRatio -> 1,
    Frame -> True,
    Epilog -> Intensity1[p, q],
    ImageSize -> {600, 600}
]

Manipulate[
    Intensity2[p, q],
    {{p, 0.25, Style["Diffraction : p", 12]}, 0, 0.5, 0.01,
        ImageSize -> Large, Appearance -> "Labeled"},
    {{q, 1, Style["Interference : q", 12]}, 1, 10, 0.01,
        ImageSize -> Large, Appearance -> "Labeled"},
    ControlPlacement -> Bottom,
    FrameMargins -> None
]

Preview :

Box

So how can I make the bottom graphics always well aligned with the graphics above it, even after we resive the whole by hand ?

$\endgroup$
1
  • $\begingroup$ I think I've found it. In the Inset, I just need to replace the coordinates {0, -0.1} to {0, -0.1}, {0, 0.5}, 60. The result is superb ! $\endgroup$
    – Cham
    Commented Apr 3, 2016 at 19:04
1
$\begingroup$

Just going to throw this in to the mix. When I saw this question, it immediately seemed perfect for Jens's function, which I modified and used previously, and in fact I have it defined in my init.m because I use it with such regularity.

I have modified the original function to respect the individual aspect ratios of the constituent plots, and the definition is in the pastebin linked below. It's a reasonably large but robust function, which I've used to combine plots for publication for years now.

Using the functions defined in the OP, this is the plotting code,

<< "http://pastebin.com/raw/1uhTgyuJ"
plotGrid[{{LumIntensity[0.25, 5, 0]}, {Intensity[0.25, 5, 
    0]}}, 600, 660, "KeepAR" -> True]

enter image description here

The plot can be interactively resized with the mouse and the overall appearance remains unchanged.

$\endgroup$
0
$\begingroup$

This can be achieved by matching a few layout options between the two charts. Namely, ImageSize, ImageMargins, ImagePadding, PlotRange, and PlotRangePadding. Scaled and Automatic can be used to simplify selection.

With

f[p_, q_, phi_, x_] := 
   (If[p > 0, Sin[2 Pi p^2 x]/(2 Pi p^2 x), 1] Cos[2 Pi p^2 q x + phi/2])^2

alignment = 
 Sequence[ImageSize -> {600, Automatic}, 
  ImageMargins -> 0, 
  PlotRangePadding -> Scaled[.02], 
  ImagePadding -> {{Scaled[.03], Scaled[.01]}, {Automatic, Automatic}}];

Then

Column[
 {DensityPlot[f[.25, 5, 0, x], {x, -30, 30}, {y, 0, 1}, 
   PlotPoints -> {1000, 2}, Frame -> None, AspectRatio -> .1, 
   Evaluate@alignment],
  Plot[f[.25, 5, 0, x], {x, -30, 30}, 
   PlotRange -> Full, Frame -> True, 
   Evaluate@alignment]},
 Spacings -> Scaled[.0005]]

enter image description here

Since we want to align along the x-axis we only need the x-axis plot range, size, padding, and margin to match between the two plots. The plot range is matched in the plot calls so alignment only contains items for size, padding, and margin. With this the plots have the same width and amount of whitespace along the x-axis and so they align.

Hope this helps.

$\endgroup$
1
  • $\begingroup$ I'm using Column instead of GraphicsColumn as I'm currently using 10.3 and it appears that GraphicsColumn is ignoring its Spacings option. $\endgroup$
    – Edmund
    Commented Apr 4, 2016 at 13:14

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.