10

I am trying to plot 2 plots together with a common x-axis and different y-axis.

I have tried implementing the modules shown in 1 Plot, 2 Scale/Axis however I do not see the full range of data in the plot, the y-axis for the second plot is truncated (at y = 400 with a few different sample data sets). The examples given in the above link do not truncate the range plotted. I would also like to modify the modules so that the x-axis commences at 1 rather than 0.

Any suggestions either to modify the module (apologies but I do not understand how the range is set to modify myself), or if there is another simple method (I need to do this many times over).

ETA: Also having difficulty adding FrameLabels to these plots. If these can be added either as an argument to the module, or otherwise that'd be useful.

TwoAxisListLinePlot[{f_, g_}] := 
 Module[{fgraph, ggraph, frange, grange, fticks, 
   gticks}, {fgraph, ggraph} = 
   MapIndexed[
    ListLinePlot[#, Axes -> True, 
      PlotStyle -> ColorData[1][#2[[1]]]] &, {f, g}]; {frange, 
    grange} = 
   Last[PlotRange /. AbsoluteOptions[#, PlotRange]] & /@ {fgraph, 
     ggraph};
  fticks = 
   Last[Ticks /. 
      AbsoluteOptions[fgraph, 
       Ticks]] /. _RGBColor | _GrayLevel | _Hue :> ColorData[1][1];
  gticks = (MapAt[Function[r, Rescale[r, grange, frange]], #, {1}] & /@
       Last[Ticks /. 
        AbsoluteOptions[ggraph, 
         Ticks]]) /. _RGBColor | _GrayLevel | _Hue -> 
     ColorData[1][2];
  Show[fgraph, 
   ggraph /. 
    Graphics[graph_, s___] :> 
     Graphics[
      GeometricTransformation[graph, 
       RescalingTransform[{{0, 1}, grange}, {{0, 1}, frange}]], s], 
   Axes -> False, Frame -> True, 
   FrameStyle -> {ColorData[1] /@ {1, 2}, {Automatic, Transparent}}, 
   FrameTicks -> {{fticks, gticks}, {Automatic, Automatic}}]]

data1 = {1, 7, 2000, 5, 4, 7, 164};
data2 = {1, 4, 3, 5, 2, 6, 8};
TwoAxisListLinePlot[{data1, data2}]

enter image description here

Esme_
  • 693
  • 4
  • 12

3 Answers3

7

The solution is in the accepted answer to the question you linked to. Only some minor modifications are required.

C1 = RGBColor[0.368, 0.507, 0.710];
C2 = RGBColor[0.881, 0.611, 0.142];

data1 = {1, 7, 2000, 5, 4, 7, 164};
data2 = {1, 4, 3, 5, 2, 6, 8};

p1 =
 ListLinePlot[
  data1,
  ImagePadding -> 45,
  Frame -> {True, True, True, False},
  FrameLabel -> "Blue Series",
  FrameStyle -> {Automatic, C1, Automatic, Automatic},
  FrameTicks -> {All, All, None, None},
  GridLines -> Automatic,
  ImageSize -> Large,
  PlotRange -> {{1, Automatic}, All},
  PlotStyle -> C1];

p2 =
 ListLinePlot[
  data2,
  Axes -> False,
  ImagePadding -> 45,
  Frame -> {False, False, False, True},
  FrameLabel -> {None, None, None, "Orange Series"},
  FrameStyle -> {Automatic, Automatic, Automatic, C2},
  FrameTicks -> {None, None, None, All},
  ImageSize -> Large,
  PlotRange -> {{1, Automatic}, All},
  PlotStyle -> C2];

Overlay[{p1, p2}]

enter image description here

eldo
  • 67,911
  • 5
  • 60
  • 168
  • The list of four elements, one for each side, somehow stopped working for FrameLabel and FrameTicks sometime between v9 and v11.1.1. The syntax that works in v11.1.1 is {{Left, Right},{Bottom,Top}}, as is discussed in https://mathematica.stackexchange.com/a/158126/46335 – FalafelPita Oct 18 '17 at 19:07
5

To fix the first issue, you need to set PlotRange->All in the first call to ListLinePlot. Then it's pretty easy to adapt this to take lots of other optional arguments as well,

TwoAxisListLinePlot[{f_, g_}, plotopts : OptionsPattern[]] := 
 Module[{fgraph, ggraph, frange, grange, fticks, 
   gticks}, {fgraph, ggraph} = 
   MapIndexed[
    ListLinePlot[#, Axes -> True, PlotRange -> All, 
      PlotStyle -> ColorData[1][#2[[1]]]] &, {f, g}]; {frange, 
    grange} = 
   Last[PlotRange /. AbsoluteOptions[#, PlotRange]] & /@ {fgraph, 
     ggraph};
  fticks = 
   Last[Ticks /. 
      AbsoluteOptions[fgraph, 
       Ticks]] /. _RGBColor | _GrayLevel | _Hue :> ColorData[1][1];
  gticks = (MapAt[Function[r, Rescale[r, grange, frange]], #, {1}] & /@
       Last[Ticks /. 
        AbsoluteOptions[ggraph, 
         Ticks]]) /. _RGBColor | _GrayLevel | _Hue -> 
     ColorData[1][2];
  Show[fgraph, 
   ggraph /. 
    Graphics[graph_, s___] :> 
     Graphics[
      GeometricTransformation[graph, 
       RescalingTransform[{{0, 1}, grange}, {{0, 1}, frange}]], s], 
   Axes -> False, Frame -> True, 
   FrameStyle -> {ColorData[1] /@ {1, 2}, {Automatic, Transparent}}, 
   FrameTicks -> {{fticks, gticks}, {Automatic, Automatic}}, 
   Evaluate[FilterRules[{plotopts}, Options[ListLinePlot]]]]]

data1 = {1, 7, 2000, 5, 4, 7, 164};
data2 = {1, 4, 3, 5, 2, 6, 8};
TwoAxisListLinePlot[{data1, data2}]

enter image description here

TwoAxisListLinePlot[{data1, data2}, FrameLabel -> {"X", "Y", , "Z"}, 
 PlotLabel -> "This is my plot", BaseStyle -> 15, ImageSize -> 600]

enter image description here

Keep in mind, this version of TwoAxisPlot will not work if you, like I, have a custom init.m file that sets certain options on all the plotting functions every time the kernel loads. Specifically, I have SetOptions[ListLinePlot, PlotRange -> All, Frame -> True, Axes -> False] load automatically, which breaks the 2 axis plotting function since it extracts the Ticks rather than the FrameTicks. An easy enough thing to fix though.

Jason B.
  • 68,381
  • 3
  • 139
  • 286
2

Another approach using rescaled data:

 numDivs=5;
 With[{ticks1 = FindDivisions[{Min@data1, Max@data1}, numDivs], 
       ticks2 = FindDivisions[{Min@data2, Max@data2}, numDivs]}, 
 ListLinePlot[{Rescale@data1, Rescale@data2}, Frame -> True, PlotRange -> All, 
  FrameTicks -> {{{Rescale@ticks1, 
       ticks1}\[Transpose], {Rescale@ticks2, 
       ticks2}\[Transpose]}, {Automatic, None}}, 
  FrameTicksStyle -> {{Darker@Blue, Darker@Darker@Red}, {Black, 
     Black}}]]

Mathematica graphics

You can adjust the number of ticks as required, FindDivisions is convenient but sometimes has its own ideas about the number of divisions it actually chooses.

image_doctor
  • 10,234
  • 23
  • 40