9
$\begingroup$

I'm wondering if it is possible to reproduce a figure like this.

figure

This is my datasets

data1 = {{{220., 0.04408}, {263.56, 0.039005}, {298.15, 
 0.03584}, {298.15, 0.0312}, {298.15, 0.03116}, {307.11, 
 0.034167}, {350.67, 0.029564}, {394.22, 0.025179}, {437.78, 
 0.020971}, {481.33, 0.01687}, {524.89, 0.012809}, {568.44, 
 0.0087698}, {612., 0.0048324}}, {{220., 0.04426881}, {263.56, 
 0.038393334}, {298.15, 0.0343651}, {298.15, 0.0343651}, {298.15, 
 0.034365}, {307.11, 0.0333877}, {350.67, 0.02889785}, {394.22, 
 0.024674893}, {437.78, 0.020577023}, {481.33, 
 0.0165636}, {524.89, 0.012658171}, {568.44, 0.0089168}, {612., 
 0.00536660}}};
 data2 = {{220., 0.428351}, {263.56, 1.568171}, {298.15, 
 4.11516}, {298.15, 10.14462}, {298.15, 10.286021}, {307.11, 
 2.2807}, {350.67, 2.2532}, {394.22, 2.0020}, {437.78, 
 1.8786732}, {481.33, 1.8159621}, {524.89, 1.177}, {568.44, 
 1.67673}, {612., 11.05458}};

And this is my complicated code:

aspectRatio = 0.7;
GraphicsColumn[{ListPlot[data1, AspectRatio -> aspectRatio1, 
Frame -> True, Axes -> False, ImageMargins -> 20, 
PlotStyle -> {Black, Red}, 
PlotMarkers -> {"\[EmptyCircle]", "\[EmptyDownTriangle]"}], 
ListPlot[data2, AspectRatio -> aspectRatio, Frame -> True, 
Axes -> False, ImageMargins -> 20, 
PlotMarkers -> {"\[EmptyCircle]"}, PlotStyle -> Black]}, 
Epilog -> 
Style[{Text["T(K)", Scaled@{.5, .02}], 
Rotate[Text[
  "|\!\(\*SubscriptBox[\(\[Sigma]\), \
\(dataset\)]\)-\!\(\*SubscriptBox[\(\[Sigma]\), \
\(calc\)]\)|/\!\(\*SubscriptBox[\(\[Sigma]\), \(dataset\)]\)", 
  Scaled@{.01, .25}], 90 Degree], 
Rotate[Text["\[Sigma] (N/m)", Scaled@{.01, .75}], 90 Degree], 
Text["\[EmptyCircle] \!\(\*SubscriptBox[\(\[Sigma]\), \
\(dataset\)]\)", Scaled@{.85, .85}], 
Text[Style[
  "\[EmptyDownTriangle] \!\(\*SubscriptBox[\(\[Sigma]\), \
\(calc\)]\)", Red], Scaled@{.835, .83}]}, 12], 
PlotRangePadding -> {0, 150}, ImageSize -> 500]

This code generates this picture that is quite similar to the first one:

fig_2

Now I'm wondering:

  1. Why the left border of the first picture isn't aligned with the second one?

  2. Is it possible to have the second picture with a different aspectRatio just like the fist one?

  3. My code is very complicated. There is a more smart way to do the same?

Cecyl.

$\endgroup$
  • $\begingroup$ Look for FrameLabel to make things easier. Also see Column and set the ImageSizes explicitly and use AspectRatio -> Full to set make the plots fill the whole space. $\endgroup$ – b3m2a1 Mar 16 '17 at 21:54
  • $\begingroup$ In addition to my answer below, I highly recommend against using font-based markers. They do not appear where you expect them to, i.e., they are useless as indicators for data points. See this post for more details. $\endgroup$ – Felix Mar 17 '17 at 2:36
8
$\begingroup$

You may use the following underlying Graphics options in combination; AspectRatio,ImageSize, and ImagePadding.

@MB1956 post gets you most of the way but does not have the required options and option values to seal the deal.

AspectRatio

Looking at the image it seems that you need the plotted area to the the same width but the top plot 4 times as tall as the bottom plot. Set AspectRatio: top as 2 / GoldenRatio; bottom as .5 / GoldenRatio.
2 is 4 times larger than .5 and they have an equal base the gives a reasonable ratio.

ImageSize

With the AspectRatio set appropriate ImageSize is next. Here we can let Mathematica do most of the work for us. It will create an image to the AspectRatio provided. Give it the width and let it determine the height Automatically. Set ImageSize as {500, Automatic} for both.

ImagePadding

Once Mathematica plots it then pads on the sides of the plots to create space for ticks, labels and the like. This is when the plotted area becomes misaligned due to different widths and/or heights of this items between the plots. However, with ImagePadding we can match the padding between the two plots so that the plotted areas remain in proportion. Here we are only concerned with the ImagePadding on the left-hand side. There are no tick or frame labels on the right-hand side so the padding will be equal by default. Set ImagePadding as {{55, All}, {All, All}} for both.

Results

Now we have options for the top plot:

AspectRatio -> 2/GoldenRatio,
ImageSize -> {500, Automatic},
ImagePadding -> {{55, All}, {All, All}}

and for the bottom plot:

AspectRatio -> .5/GoldenRatio,
ImageSize -> {500, Automatic},
ImagePadding -> {{55, All}, {All, All}}

Use these in @MB1956 post and adjust the FrameLabels so they print in mathematical format.

Column@{
  ListPlot[data1,
   Frame -> True, 
   FrameLabel -> {{Row@{"σ", (("N")/("m"))}, None}, {None, None}},
   PlotStyle -> {Black, Red}, 
   PlotMarkers -> {"○", "▽"},
   PlotLegends -> 
    Placed[{Subscript["σ", "dataset"], Style[Subscript["σ", "calc"], Red]}, 
      {Scaled[{.95, 0.8}], {Right, Center}}],
   AspectRatio -> 2/GoldenRatio,
   ImageSize -> {500, Automatic},
   ImagePadding -> {{55, All}, {All, All}}]
  ,
  ListPlot[data2,
   Frame -> True, Axes -> False, 
   FrameLabel -> {{Subscript["σ", "dataset"] - 
       Subscript["σ", "calc"]/Subscript["σ", "dataset"],None}, 
       {"T(K)", None}},
   PlotMarkers -> {"○"}, PlotStyle -> Black,
   AspectRatio -> .5/GoldenRatio,
   ImageSize -> {500, Automatic},
   ImagePadding -> {{55, All}, {All, All}}]
  }

Mathematica graphics

There are other padding and margin options that you will find under Graphics and the functions themselves.

Hope this helps.

$\endgroup$
  • $\begingroup$ Thanks a lot for your deep explanation! $\endgroup$ – Cecil Mar 17 '17 at 7:57
  • $\begingroup$ @Cecil I seem to have missed a set of brackets on the lower plot's frame label formula. If you add them then the formula will display as expected. Also, notice that the plotted areas are not exactly 4 to 1 tall due to the extra padding below the lower plot for the frame label. You can add a bit to the lower plots aspect height by using .7 instead of .5 in the AspectRatio. $\endgroup$ – Edmund Mar 17 '17 at 12:31
7
$\begingroup$

I recommend having a look at SciDraw for plotting and MaTeX for typesetting of Greek symbols.

It requires a few moments to familiarize yourself with the syntax, but then it is really easy to produce high quality plots with clean code. For your example:

(* Load the packages *)
Needs["SciDraw`"];
Needs["MaTeX`"];

(* Define the style *)
DefineStyle[
  "symbol1", {DataLine -> {Show -> False}, 
   DataSymbol -> {SymbolSize -> 7, SymbolShape -> "Circle", 
     ShowFill -> False}}];
DefineStyle[
  "symbol2", {DataLine -> {Show -> False}, 
   DataSymbol -> {SymbolSize -> 7, SymbolShape -> "DownTriangle", 
     ShowFill -> False, LineColor -> Red}}];

Figure[
 Multipanel[{
   FigurePanel[ (* First panel *)
    {
     DataPlot[data1[[1]], DataColumns -> {1, 2}, Style -> "symbol1"];
     DataPlot[data1[[2]], DataColumns -> {1, 2}, Style -> "symbol2"];
     DataLegend[Scaled[{0.75, 0.85}],
      {
       {"symbol1", MaTeX["\\sigma_\\text{dataset}"]},
       {"symbol2", MaTeX["\\sigma_\\text{calc}"]}
       }
      ];
     },
    {1, 1},(* Panel position (row, column) *)

    XPlotRange -> {200, 620},
    YPlotRange -> {0, 0.05},
    XTicks -> LinTicks[200, 620],
    YTicks -> LinTicks[0, 0.05],
    YFrameLabel -> MaTeX["\\sigma(\\text{N/m})"]
    ];
   FigurePanel[ (* Second panel *)
    {
     FigGraphics[
      ListPlot[data2, PlotMarkers -> {"\[EmptyCircle]"}, 
       PlotStyle -> Black]
      ]
     },
    {2, 1},(* Panel position (row, column) *)        
    XPlotRange -> {200, 620},
    YPlotRange -> {0, 11},
    XTicks -> LinTicks[200, 620],
    YTicks -> LinTicks[0, 11],
    XFrameLabel -> MaTeX["T(\\text{K})"],
    YFrameLabel -> 
     MaTeX["\\frac{\\sigma_\\text{dataset}-\\sigma_\\text{calc}}{\\\
sigma_\\text{dataset}}"]
    ];
   },
  Dimensions -> {2, 1}, (* number of rows, number of columns *)

  YPanelGaps -> 0.1,
  YPanelSizes -> {2, 1}, (* 
  Make the top plot twice as large as the bottom one *)      
  PanelLetter -> None
  ],
 CanvasSize -> {4, 6}
 ]

The code might be lengthy but in my opinion it is much easier to read than these endless chains of arguments you need to set to make regular plots look decent. Also, plots are guaranteed to align well.

enter image description here

$\endgroup$
  • $\begingroup$ This is what I need. Thanks! $\endgroup$ – Cecil Mar 17 '17 at 7:57
  • $\begingroup$ I find SciDraw so verbose. Perhaps I just haven't found the tipping point where SciDraw produces an equivalent image in less and/or easier to read code than direct Wolfram Language functions and options. $\endgroup$ – Edmund Mar 17 '17 at 12:40
  • $\begingroup$ @Edmund I guess in the end it's a matter of taste. But considering how many questions about alignment issues in multi panel plots have been posted and highly ranked here, I would say the main argument is that panels are guaranteed to be aligned. $\endgroup$ – Felix Mar 17 '17 at 16:35
2
$\begingroup$

So I mentioned in my comment a number of ways to do this, but there are enough features to your plots I think it's worth just giving sample code and explaining what each part does, as a demo, really:

First, here's the code:

Column[{
  ListPlot[data1,
   Frame -> True,
   FrameLabel -> {{"\[Sigma] (N/m)", None}, {None, None}},
   ImageSize -> {500, 500},
   AspectRatio -> Full,
   PlotStyle -> {Black, Red},
   PlotMarkers -> {"\[EmptyCircle]", "\[EmptyDownTriangle]"},
   PlotLegends ->
    Placed[{
      Subscript["\[Sigma]", "dataset"],
      Style[Subscript["\[Sigma]", "calc"], Red]
      },
     {Scaled[{.95, 0.8}], {Right, Center}}
     ]
   ],
  ListPlot[data2,
   Frame -> True,
   Axes -> False,
   FrameLabel -> {
     {Row@{Subscript["\[Sigma]", "dataset"], "-",
        Subscript["\[Sigma]", "calc"], "/", 
        Subscript["\[Sigma]", "dataset"]}, None},
     {"T(K)", None}},
   ImageSize -> {500, 250},
   AspectRatio -> Full,
   PlotMarkers -> {"\[EmptyCircle]"},
   PlotStyle -> Black]
  }
 ]

And here's what the result looks like:

plots

Now let's take this apart. What did I change?

The very first thing is that I'm just using a standard Column instead of GraphicsColumn. Not strictly necessary, but I think it's more typical.

The first substantive thing I did was use FrameLabel as you had Frame -> True. This is the Frame counter part of AxesLabel. Note that it takes a {{left,right},{bottom,top}} syntax, much like all the frame / margin stuff in Mathematica.

Note that I converted your strings with boxes in them to simpler Row based expressions. When possible I like to keep boxes (essentially formatting) out of my strings.

Then I explicitly set the ImageSizes and used AspectRatio -> Full to fill both of those sizes. I think this affords the most control over the graphics sizing, so it's what I like to do.

Last I used PlotLegends with Placed to put the labels you had put in by hand on the plot. Note that the plot marker is naturally situated next to the label. The syntax here is Placed[label, {Scaled[{% of width, % of height}], {horizontal anchor, vertical anchor}].

Also I didn't do this here, but if you make the y-axis data for your second plot also go out to three points of precision, the frames should align.

$\endgroup$
  • $\begingroup$ The frames of the two figures are not aligned. $\endgroup$ – Johu Mar 17 '17 at 0:52
  • $\begingroup$ @Johu see the last paragraph in my answer. $\endgroup$ – b3m2a1 Mar 17 '17 at 0:57
  • $\begingroup$ @Ceil glad to help. Consider accepting either Edmund or Felix's answer if they answered your question. It's nice for them and signals to people that the problem has been suitably solved. $\endgroup$ – b3m2a1 Mar 17 '17 at 16:22

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.