4
$\begingroup$

I have four datasets (dataA, dataB, dataC, dataD), out of which two have the same plot range of X axis and rest two have different range of X axis. Here is the code:

dataA = {{0, 80}, {0.01, 40}, {0.02, 20}, {0.05, 10}};

dataB = {{0, 80}, {0.01, 65}, {0.05, 10}, {0.1, 12}, {0.2, 
    020}, {0.3, 25}, {0.375, 51}};

dataC = {{0, 80}, {0.5, 65}, {010, 89}, {50, 110}, {100, 
    121}, {300, 135}};

dataD = {{0, 80}, {30, 200}, {150, 350}, {300, 470}};

Plot1 = 
 ListPlot[{dataA, dataB}, PlotRange -> Automatic, 
  PlotMarkers -> {●, ▼}, 
  PlotStyle -> {Blue, Green}]

enter image description here

Plot2 = 
     ListPlot[{dataC, dataD}, PlotRange -> Automatic, 
      PlotMarkers -> {▲, ■}, 
      PlotStyle -> {Gray, Red}]
    
    

enter image description here

Show[Plot2, Plot1]
    

enter image description here

Now when I merge both plots (Plot1 and Plot2 by using Show) some data sets are not visualised, Data points of plot1 are showing just like a point, I understand that I need to break X axis, but I could not do it in mathematica. Any help will be great for me, i am using mathematica 9.

$\endgroup$
2
  • $\begingroup$ I think you may try using Overlay. Use Frame->True for each plot and label the two sets of ticks on two different edges. Then overlay the two plots. What Show does is combining all graphic elements on the same canvas with their specified positions; this is why the range of your dataA dataB looks really narrow. $\endgroup$
    – Gravifer
    Mar 20, 2021 at 6:47
  • $\begingroup$ Have you considered a different layout, using ListLogLinearPlot? $\endgroup$
    – corey979
    Mar 20, 2021 at 11:40

4 Answers 4

5
$\begingroup$

As shown by @kglr, you can use ResourceFunction["PlotGrid"] for this purpose. With the "MergeAxes" option, you can even get nice axes breaks. Since in your case, both axes of the plots are wildly different, we can create a 2x2 grid of plots and fill the two empty corners with Graphics[{},Frame->True] type plots:

ResourceFunction["PlotGrid"][
 {
  {
   Graphics[{}, PlotRange -> 10000, Frame -> True],
   Show[Plot2, PlotRange -> {Automatic, {85, Automatic}}, Frame -> True]
   },
  {
   Show[Plot1, Plot2, Frame -> True],
   Frame[Graphics[{}, PlotRange -> 10000, Frame -> True]]
   }
  },
 PlotRange -> Min,
 "MergeAxes" -> "Cut",
 Spacings -> 10,
 ItemSize -> {{1, 2}, 1}
 ]

enter image description here

Some notes:

  • The current version of PlotGrid has an issue that causes too many axes break indicators to appear. I have submitted a fixed version, in the meantime you can manually work around this issue as shown at the bottom of this answer Note: This has been fixed by now
  • I set the PlotRange of the two filler plots to a large value so that I can then use PlotRange->Min on the entire PlotGrid to make all ranges consistent (the 10000 essentially needs to be bigger than all plots ranges, such that the range of the actual plots is chosen). Alternatively you could set the plot ranges of the two filler plots manually, but that would require a lot of tweaking.
  • I set the ItemSize of the first column to be smaller than the second to somehow hint at the fact that the first column covers a way smaller range. This can obviously be removed/tweaked if desired
  • I combine the two plots in the bottom left to ensure that any points from Plot2 in the range of Plot1 are also shown
  • I tweak the PlotRange of Plot2 slightly so that the vertical ranges of the two rows don't overlap
  • I set Frame->True for all plots since that's needed for PlotGrid to give us a nice frame with broken axes

Workaround

Note: the underlying issue has been fixed, so this is no longer relevant

As noted above, the current version of PlotGrid has an issue that causes too many axes break indicators to appear:

enter image description here

To work around the issue until the updated version is accepted, we can manually set the FrameStyle of all four plots to have invisible (white) frames in towards the middle, and grey frames on the outside:

ResourceFunction["PlotGrid"][
 {
  {
   Graphics[{}, PlotRange -> 10000, Frame -> True,
    FrameStyle -> {{GrayLevel[0.4], White}, {White, GrayLevel[0.4]}}
    ],
   Show[Plot2, PlotRange -> {Automatic, {85, Automatic}},
    FrameStyle -> {{White, GrayLevel[0.4]}, {White, GrayLevel[0.4]}}
    ]
   },
  {
   Show[Plot1, Plot2,
    FrameStyle -> {{GrayLevel[0.4], White}, {GrayLevel[0.4], White}}
    ],
   Frame[Graphics[{}, PlotRange -> 10000, Frame -> True,
     FrameStyle -> {{White, GrayLevel[0.4]}, {GrayLevel[0.4], White}}]
    ]
   }
  },
 PlotRange -> Min,
 "MergeAxes" -> "Cut",
 Spacings -> 10,
 ItemSize -> {{1, 2}, 1}
 ]
$\endgroup$
2
  • $\begingroup$ Thank you, I am using Mathematica version 9. In another pc I have version 10, however, ResourceFunction is useful in mathematica 12. So has there any alternatives which work in 9? $\endgroup$
    – P Pyne
    Mar 22, 2021 at 7:23
  • $\begingroup$ @PPyne You can try to download the paclet version of PlotGrid from here. To use it, install the paclet with PacletInstall["path/to/PlotGrid-4.2.0.paclet"], and then simply replace ResourceFunction["PlotGrid"] by PlotGrid in the code. I tested it in 10.4 (version 9 does not work), and it seems to mostly work. (the documentation page looks a bit funny sometimes because it was not designed for older versions) $\endgroup$
    – Lukas Lang
    Mar 22, 2021 at 13:39
3
$\begingroup$

You can use Lukas Lang's ResourceFunction["PlotGrid"]:

ResourceFunction["PlotGrid"][{
   {ListPlot[{dataA, dataB}, PlotRange -> Automatic, 
    Frame -> True, 
    PlotMarkers -> {●, ▼}, 
    PlotStyle -> {Blue, Green}], 
   ListPlot[{dataC, dataD}, PlotRange -> Automatic, Frame -> True, 
    FrameTicks -> {{Automatic, All}, {Automatic, Automatic}}, 
    PlotMarkers -> {▲, ■}, 
    PlotStyle -> {Gray, Red}]}}, 
 ImageSize -> Large, AspectRatio -> 1/2]

enter image description here

Use the options Spacings -> Scaled[.02] and "ShowFrameLabels" -> Automatic to get:

enter image description here

To have the two plots separated with divider line with no ticks, use

ResourceFunction["PlotGrid"][{
  {ListPlot[{dataA, dataB}, PlotRange -> Automatic, 
    Frame -> {{True, False}, {True, True}}, 
    PlotMarkers -> {●, ▼}, 
    PlotStyle -> {Blue, Green}], 
   ListPlot[{dataC, dataD}, PlotRange -> Automatic, Frame -> True, 
    FrameTicks -> {{None, All}, {Automatic, Automatic}}, 
    PlotMarkers -> {▲, ■}, 
    PlotStyle -> {Gray, Red}]}}, 
   ImageSize -> Large, AspectRatio -> 1/2]

enter image description here

$\endgroup$
2
$\begingroup$

Actually, the breaking of the X-axis is not trivial in MMA. Let's say, we have such data sets that exist in different x-ranges:

da = Table[{i, Log[i + 0.0001] Sin[12 Pi i]}, {i, 0, 0.1, 0.02}];
db = Table[{i, i^1.1 Sin[18 Pi i]}, {i, 0.5, 6, 0.2}];

Then we can draw them altogether using following simple way:

ma = MinMax[da[[All, 2]]];
mb = MinMax[db[[All, 2]]];
mm = Abs /@ {Min@Flatten@{ma, mb}, Max@Flatten@{ma, mb}};

mrk = Graphics[{Black, Thin,
    Line@{{{-0.05, -0.1}, {0.05, 0.1}},
      {{0.05, -0.1}, {0.15, 0.1}}}
    }, ImageSize -> 20];

pos=0.88;

res = GraphicsRow[{
   ListPlot[da,
    ImagePadding -> {{30, 0}, {30, 5}},
    PlotRange -> {{-0.005, 0.125}, {-1.2 First@mm, 1.2 Last@mm}},
    Frame -> True,
    FrameStyle -> {{Black, White}, {Black, Black}},
    ImageSize -> {500, 350}],
   ListPlot[db,
    ImagePadding -> {{0, 30}, {30, 5}},
    PlotRange -> {{0.35, 6}, {-1.2 First@mm, 1.2 Last@mm}},
    Frame -> True,
    FrameStyle -> {{White, Black}, {Black, Black}},
    ImageSize -> {500, 350}]
   },
  Spacings -> 0,
  Alignment -> Left,
  Epilog -> {
    Inset[mrk, Scaled@{pos, 0.15}],
    Inset[mrk, Scaled@{pos, 0.915}]}
  ]

enter image description here

There are some important things about this workaround:

  1. the pos defines the x-position of marks that show break position. It should be adjusted manually for better view (in range 0-2).
  2. The ImageSize definition in ListPlot's should be with height values (they need to be adjusted for the aspect ratio of plots) otherwise the plots will not coincide at the middle.
  3. Other values of plot heights require the another vertical positions for break markers inside the Inset because they have defined in Scaled form for simplicity.
$\endgroup$
1
  • 1
    $\begingroup$ FYI, You can use ResourceFunction["PlotGrid"] with the "MergeAxes" option to automate the creation of such plots, e.g. ResourceFunction["PlotGrid"][{{ListPlot[da, Frame -> True], ListPlot[db, Frame -> True]}}, PlotRange -> Max, "MergeAxes" -> "Cut", Spacings -> 10] $\endgroup$
    – Lukas Lang
    Mar 20, 2021 at 15:37
0
$\begingroup$

Try using Overlay (an example from my comment):

Plot1 = 
  ListPlot[{dataA, dataB}, PlotRange -> Automatic, 
    PlotMarkers     -> {●, ▼}, 
    PlotStyle       -> {Blue, Green}, Frame -> True, 
    FrameTicks      -> {{All, {{0, 400}}}, {All, {{0, 400}}}}, 
    FrameTicksStyle -> {{Automatic, Opacity[.0]}, {Automatic, Opacity[.0]}}]

Plot2 = 
  ListPlot[{dataC, dataD}, PlotRange -> Automatic, 
    PlotMarkers     -> {▲, ■}, 
    PlotStyle       -> {Gray, Red}, Frame -> True, 
    FrameTicks      -> {{{{0, 80}}, All}, {{{0, 80}}, All}}, 
    FrameTicksStyle -> {{Opacity[.0], Automatic}, {Opacity[.0], Automatic}}]
Overlay[{Plot1, Plot2}]

Output

You will of course need labels to clarify which is which, but this is basically the gist of it.

$\endgroup$
1
  • 2
    $\begingroup$ FYI, you can use ResourceFunction["CombinePlots"] with the "AxesSides" option to automate the creation of such plots, e.g. ResourceFunction["CombinePlots"][Show[Plot1, Frame -> True], Show[Plot2, Frame -> True], "AxesSides" -> "TwoXY"] $\endgroup$
    – Lukas Lang
    Mar 20, 2021 at 15:40

Your Answer

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

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