163
$\begingroup$

enter image description here

I would like to plot those two datasets on top of each other. But they have very different range on the $y$ axis. How can I have two different axis?

I found the following on the help menu but quite esoteric for me and I can`t adapt it to data (vs. function):

TwoAxisPlot[{f_, g_}, {x_, x1_, x2_}] := 
 Module[{fgraph, ggraph, frange, grange, fticks, 
   gticks}, {fgraph, ggraph} = 
   MapIndexed[
Plot[#, {x, x1, x2}, Axes -> True, 
  PlotStyle -> ColorData[1][#2[[1]]]] &, {f, g}]; {frange, 
grange} = (PlotRange /. AbsoluteOptions[#, PlotRange])[[
  2]] & /@ {fgraph, ggraph}; fticks = N@FindDivisions[frange, 5]; 
 gticks = Quiet@
Transpose@{fticks, 
  ToString[NumberForm[#, 2], StandardForm] & /@ 
   Rescale[fticks, frange, grange]}; 
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, Automatic}}, 
    FrameTicks -> {{fticks, gticks}, {Automatic, Automatic}}]]
$\endgroup$
5
  • 3
    $\begingroup$ You'll find a lot of info with this search: groups.google.com/forum/#!searchin/… $\endgroup$
    – Szabolcs
    Jan 24, 2012 at 17:20
  • $\begingroup$ @Szabolcs, Thank You I found the above bouncing from your link ! $\endgroup$
    – 500
    Jan 24, 2012 at 17:33
  • 1
    $\begingroup$ You can start by replacing the appropriate line: {fgraph, ggraph} = MapIndexed[ListPlot[#, Axes -> True, Joined -> True, PlotStyle -> ColorData[1][#2[[1]]]] &, {f, g}];. $\endgroup$ Jan 24, 2012 at 17:35
  • $\begingroup$ Ooh, this is an ancient one, I remember implementing my own version some 5 years before. $\endgroup$ Jan 24, 2012 at 18:16
  • 8
    $\begingroup$ Come on, am I the only one who finds "2 scales, 1 plot" hilarious? $\endgroup$
    – Aron
    May 12, 2014 at 11:57

12 Answers 12

164
$\begingroup$

This can be done with Overlay if the ImagePadding and the horizontal range for each plot is the same. For example,

plot1 = ListLinePlot[
    Accumulate[RandomReal[{0, 1}, {100}]],
    PlotStyle -> Blue,
    ImagePadding -> 25,
    Frame -> {True, True, True, False},
    FrameStyle -> {Automatic, Blue, Automatic, Automatic}
]

Plot 1

plot2 = ListLinePlot[
    Accumulate[RandomReal[{0, 100}, {100}]],
    PlotStyle -> Red,
    ImagePadding -> 25,
    Axes -> False,
    Frame -> {False, False, False, True},
    FrameTicks -> {{None, All}, {None, None}},
    FrameStyle -> {Automatic, Automatic, Automatic, Red}
]

Plot 2

Overlay[{plot1, plot2}]

Double-axis plot

Edit: Cleared up which axis is which using FrameStyle.

$\endgroup$
13
  • 2
    $\begingroup$ BTW +1 for using Overlay :-) I never managed to make good use of it. $\endgroup$
    – Szabolcs
    Jan 24, 2012 at 19:01
  • 2
    $\begingroup$ @P.Fonseca I guess you could do it if you specified the ticks in an interleaved fashion. But I wouldn't want to read a plot like that, would you? I prefer to stack up plots with a single pair of axes. $\endgroup$ Jan 24, 2012 at 22:52
  • 5
    $\begingroup$ Setting PlotRange -> All or PlotRange -> Full breaks the numbering on the right-hand axis. Any idea why, and how to fix it? $\endgroup$ Apr 16, 2013 at 3:33
  • 2
    $\begingroup$ @BenjaminHodgson using FrameTicks -> All instead of the proposed solution solved it for me. $\endgroup$
    – Valacar
    Jan 23, 2017 at 9:11
  • 3
    $\begingroup$ Nice solution. Minor update. Version 11 requires all the frame specifiers to be {{left, right},{top, bottom}} form for this to work. Using old form as shown leads to no axis scale on right. $\endgroup$ Feb 20, 2018 at 7:06
37
$\begingroup$

As I said, it's pretty easy to adapt the TwoAxisPlot[] function given in the OP. I'll give two flavors here, named TwoAxisListPlot[] and TwoAxisListLinePlot[]:

TwoAxisListPlot[{f_, g_}] := 
 Module[{fgraph, ggraph, frange, grange, fticks, 
   gticks}, {fgraph, ggraph} = 
   MapIndexed[
    ListPlot[#, 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}}]]

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}}]]

Test:

d1 = Accumulate[RandomReal[{0, 1}, {100}]];
d2 = Accumulate[RandomReal[{0, 50}, {100}]];
GraphicsGrid[{{ListLinePlot[d1], ListPlot[d2]},
             {TwoAxisListPlot[{d1, d2}], TwoAxisListLinePlot[{d1, d2}]}}]

two-axis plots

$\endgroup$
12
  • 9
    $\begingroup$ If anybody's interested, I could modify the functions a bit to take options (e.g. nondefault colors for the two plots)... $\endgroup$ Jan 25, 2012 at 3:45
  • $\begingroup$ I would definitely be interested to add options I like to customize my plot a lot. Would it be possible for the function to take all the ListPlot option. Many thanks for your answer and attention. $\endgroup$
    – 500
    Jan 25, 2012 at 7:32
  • $\begingroup$ That would take a fair bit of effort. Would you mind a wait of a few days? $\endgroup$ Jan 25, 2012 at 7:50
  • $\begingroup$ TwoAxisListPlot does not work on version 7, but TwoAxisListLinePlot does. Can you tell why? $\endgroup$
    – Mr.Wizard
    Jan 25, 2012 at 16:30
  • $\begingroup$ @Mr.Wizard I don't quite know why; I don't have version seven to test it on. What exactly happens? $\endgroup$ Jan 25, 2012 at 22:11
29
$\begingroup$

Even though this question has been flagged as answered, I think the answers are more complicated than they need to be (with respect to the authors). I offer the following, which takes advantage of FrameTics:

(*create 2 lists*)
x1 = Accumulate[RandomVariate[NormalDistribution[0, 1], 100]];
x2 = 25 Accumulate[RandomVariate[NormalDistribution[0, 1], 100]];

(*set nice plot options*)
SetOptions[ListPlot, ImageSize -> 500, Frame -> True, Joined -> True, 
GridLines -> Automatic, PlotStyle -> {{Thick, Red}, {Thick, Blue}}, 
PlotRange -> {{0, 100}, {-50, 50}}, 
FrameLabel -> {"Progress", "Red Line","Descriptive Title", "Blue line"}, 
 LabelStyle -> {12, FontFamily -> "Arial"}];

(*display, using FrameTicks for the bottom axis to show what it does*)
ListPlot[{x1, x2},FrameTicks -> {{{0, "Beginning"}, {25, "Early"},
{50, "Middle"},{75,"Almost\nFinished"}, {100, "Finished"}}, Automatic, None,Automatic}]

Mathematica graphics

As expected, x2 goes off ListPlot's range and needs a different scale. This can be accomplished by rescaleing x2 and using FrameTics to create a rescaled axis on the right. First, rescale x2 using the function rescaled[]:

datamax = Max[x2]; datamin = Min[x2];
datarange = datamax - datamin;
plotrange = 100; plotmin = -50;
rescaled[x_] := (x - datamin) plotrange/datarange + plotmin

Next, create new axis lables for the right axis::

axeslabel[v_] := {rescaled[v], ToString[v]}
rightaxis = Table[axeslabel[v], {v, -500, 500, 100}]

Finally, create the new ListPlot:

lp = ListPlot[{x1, x3},FrameTicks -> {{{0, "Beginning"}, {25, "Early"}, {50, 
  "Middle"}, {75, "Almost\nFinished"}, {100, "Finished"}}, Automatic, None, rightaxis}]
x3 = rescaled[#] & /@ x2;

Mathematica graphics

See how easy that was!

Upon reflection my approach isn't too different from Peter Breitfeld's, except perhaps that I made a more general rescaling routine.

$\endgroup$
2
  • $\begingroup$ Thank you George. Which version of MMA that you used? $\endgroup$
    – Nam Nguyen
    Oct 15, 2020 at 9:46
  • $\begingroup$ I guess that it was the most current vs at the time. It was five years ago, and we have one release a year, so probably version 5. Did you try to do this with a more recent version, but it didn't work? $\endgroup$ Nov 16, 2020 at 18:25
27
$\begingroup$

Hope is the last to die. Nine years later, we finally have a native multi-axis implementation.

ListLinePlot[
    {PrimePi[Range[100]], EulerPhi[Range[100]]}
    ,MultiaxisArrangement -> All
]

Here is the link to the official documentation.

enter image description here

$\endgroup$
2
  • 2
    $\begingroup$ Nice. Does anybody know why this is limited to ListPlot and not included to Plot and family members? $\endgroup$ Dec 14, 2021 at 9:17
  • $\begingroup$ many of the plot options are not available with this solution unfortunately. for example you cannot specify the plot range. $\endgroup$
    – elbOlita
    Jan 17 at 10:09
19
$\begingroup$

Most compatible solution:

The solutions provided are not compatible with plots that contain labels. Here's a solution with possibility to add options:

TwoAxisListPlot[{f_, g_}, opts___] := 
 Module[{fgraph, ggraph, frange, grange, fticks, 
   gticks}, {fgraph, ggraph} = 
   MapIndexed[
    ListPlot[#, Axes -> True, PlotStyle -> ColorData[1][#2[[1]]], 
      opts] &, {f, g}]; {frange, 
    grange} = (PlotRange /. 
        AbsoluteOptions[#, PlotRange])[[2]] & /@ {fgraph, ggraph}; 
  fticks = N@FindDivisions[frange, 5];
  gticks = 
   Quiet@Transpose@{fticks, 
      ToString[NumberForm[#, 2], StandardForm] & /@ 
       Rescale[fticks, frange, grange]};
  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, Automatic}}, 
   FrameTicks -> {{fticks, gticks}, {Automatic, Automatic}}]]

And here's how it's called:

TwoAxisListPlot[{Accumulate[RandomReal[{0, 1}, {100}]], 
  Accumulate[RandomReal[{0, 1}, {100}]]}, {Frame -> True, 
  PlotLabel -> "Hello there!", PlotRange -> All, Joined -> True, 
  PlotMarkers -> {Automatic, Small}, ImageSize -> Large, 
  FrameLabel -> {{"Mean magnetic field (T)", 
     "(Hz)"}, {"Some parameter", ""}}, BaseStyle -> {FontSize -> 16}}]

enter image description here

$\endgroup$
5
  • $\begingroup$ Nice solution, however the scaling appears to have gone wrong, I notice the y-axis plots I was conducting were not aligning perfectly with the y-axis, it was slightly out. Please can you check and fix. $\endgroup$
    – SPIL
    Sep 30, 2018 at 13:07
  • $\begingroup$ @SPIL sorry man. I haven't worked on Mathematica in a while. $\endgroup$ Sep 30, 2018 at 14:21
  • $\begingroup$ Have you switched to using R instead then? $\endgroup$
    – SPIL
    Sep 30, 2018 at 15:07
  • $\begingroup$ @SPIL I used to be in science/academia. Now I'm a professional software developer. I don't need Mathematica anymore because I used to use it for data analysis. $\endgroup$ Sep 30, 2018 at 16:15
  • $\begingroup$ @The Quantum Physicist, I'm testing this in V12, the PlotRange -> All is working well, but if I want to specify the PlotRange values for both two verticle axes, it doesn't seem to let me. Is there a way of doing it? $\endgroup$
    – Gvxfjørt
    Mar 9, 2020 at 12:17
15
$\begingroup$

If you want to use David Park's Presentations package, you can reset the ticks and it will look like this:

data1 = {{1, 1.1}, {2, 1.5}, {3, 0.9}, {4, 2.3}, {5, 1.1}};
data2 = {{1, 1001.1}, {2, 1001.5}, {3, 1000.9}, {4, 1002.3}, {5, 1001.1}};

<<Presentations`
crop[x_] := (x - 1000)
Draw2D[
 {
  {Red, Thickness[0.02], Opacity[0.3], 
   ListDraw[data1, Joined -> True]},
  Blue, ListDraw[{#1, crop[#2]} & @@@ data2, Joined -> True]
  },
 AspectRatio -> 1/GoldenRatio,
 Frame -> True,
 FrameTicks -> {{Automatic,
      CustomTicks[crop, {1001, 1002.2, 0.2, 5},
         CTNumberFunction -> (Style[#, FontColor -> Blue] &)]},
   {Automatic, Automatic}},
 PlotLabel -> Row[{Style["data1", Red], ", ", Style["data2", Blue]}],
 PlotRange -> All
 ]

Mathematica graphics

$\endgroup$
15
$\begingroup$

Here is just a quick update of J.M.'s code to use some newer (read undocumented) functions in the Charting`context.

TwoAxisListPlot[{list1_, list2_}, opts : OptionsPattern[]] := 
 Module[{plot1, plot2, ranges},
  {plot1, plot2} = ListLinePlot /@ {list1, list2};
  ranges = Last@Charting`get2DPlotRange@# & /@ {plot1, plot2};
  ListPlot[
   {list1, Rescale[list2, Last@ranges, First@ranges]},
   Frame -> True,
   FrameTicks -> {{Automatic, 
      Charting`FindTicks[First@ranges, Last@ranges]}, {Automatic, 
      Automatic}},
   FrameStyle -> {{Automatic, ColorData[97][2]}, {Automatic, 
      Automatic}},
   FilterRules[{opts}, Options[ListPlot]]
   ]
  ]

d1 = Accumulate[RandomReal[{0, 1}, {100}]];
d2 = Accumulate[RandomReal[{0, 50}, {100}]];
GraphicsGrid[{{ListLinePlot[d1], 
   ListPlot[d2]}, {TwoAxisListPlot[{d1, d2}], 
   TwoAxisListPlot[{d1, d2}, Joined -> True]}}]

enter image description here

$\endgroup$
3
  • 1
    $\begingroup$ Superb! This should be a Mathematica builtin function! $\endgroup$
    – grbl
    Feb 14, 2017 at 20:22
  • 1
    $\begingroup$ @grbl - Thanks! You should take a second and send them a message, wolfram.com/support/contact , even linking here if you like. The more users who request a feature, the more likely it will be hooked up. $\endgroup$
    – Jason B.
    Feb 14, 2017 at 20:47
  • 1
    $\begingroup$ It's been requested by many users since the 90s $\endgroup$ Apr 26, 2017 at 0:22
14
$\begingroup$

Using ResourceFunction["CombinePlots"], you can combine arbitrary plots into two-axes plots, without the need to create a new version for every type of plot:

ResourceFunction["CombinePlots"][
 ListLinePlot[
  Accumulate[RandomReal[{0, 1}, {100}]],
  PlotStyle -> Blue, Frame -> True, FrameStyle -> Blue
  ],
 Plot[
  x^2, {x, 10, 100},
  PlotStyle -> Red, Frame -> True, FrameStyle -> Red
  ],
 "AxesSides" -> "TwoY"
 ]

enter image description here

Note that the frame styles of the two plots where automatically applied to the appropriate axes, and that it is easy to combine Plot together with ListPlot. (CombinePlots also works with different ScalingFunctions etc, see the documentation for more details & examples)

$\endgroup$
1
  • $\begingroup$ Thanks! This works seamlessly with DateListPlot[]. I can even use the PlotLegends option in each subplot and then the combined plot has the correct legend. $\endgroup$ Jul 8, 2021 at 20:16
13
$\begingroup$

I needed a easy to modify "TwoAxisDateListPlot".

Thanks ArgentoSapiens for the inspiration. Here is my version.

list1 = FinancialData["GE", "Feb. 5, 2014"];
list2 = FinancialData["Gold", "March. 5, 2014"];
TwoAxisDateListPlot3[list1, list2, AspectRatio -> 0.3, ImageSize -> Large]

enter image description here

ClearAll[TwoAxisDateListPlot3]
Needs["Calendar`"];
TwoAxisDateListPlot3[dat1__, dat2__, opts : OptionsPattern[]] := Block[
{data1 = dat1, data2 = dat2, plot1, plot2, userOptions,defaultOptions, minx, maxx, temp},
(* display two datelist-graphs on one diagram *)

(* span x *)
If[DateQ[data1[[1, 1]]] (* find out date format *),
temp = SortBy[data1[[;; , 1]]~Join~data2[[;; , 1]], AbsoluteTime];
minx = temp[[1]]; maxx = temp[[-1]],
minx = Min[{data1[[;; , 1]], data2[[;; , 1]]}]; 
maxx = Max[{data1[[;; , 1]], data2[[;; , 1]]}]
];

(* get options *)
userOptions = FilterRules[{opts}, Options[DateListPlot]];
defaultOptions = FilterRules[{PlotRange -> {{minx, maxx}, {All, All}}, 
ImagePadding -> {{40, 40}, {25, 5}}}, Options[DateListPlot]];

(* do the plots *)
plot1 = DateListPlot[data1, PlotStyle -> Blue, 
  Frame -> {{True, False}, {True, True}},
  FrameStyle -> {Directive[FontFamily -> "Helvetica", Bold], 
  Directive[FontFamily -> "Helvetica", Bold, Blue], Automatic, 
  Automatic}, userOptions, defaultOptions] // Quiet;
plot2 = DateListPlot[data2, PlotStyle -> Darker[Green], Axes -> False, 
  Frame -> {{False, True}, {False, False}},
  FrameTicks -> All,
  FrameStyle -> {Automatic, Automatic, Automatic, 
    Directive[FontFamily -> "Helvetica", Bold, Darker[Green]]}, 
  userOptions, defaultOptions] // Quiet;
Overlay[{plot1, plot2}]];
$\endgroup$
3
  • $\begingroup$ What is DateQ? It seems not to a buit-in. $\endgroup$
    – iav
    Jul 30, 2015 at 11:40
  • 3
    $\begingroup$ @iav It is loaded by Needs["Calendar`"] $\endgroup$
    – Mr.Wizard
    Aug 4, 2015 at 6:50
  • $\begingroup$ How can make a FrameLabel appear if the scale of one of the axes is such that ticks like 0.0001, 0.0002, etc. are displayed (the point is that it essentially requires 5 digits plus a dot to show the scale of the axis and hence the corresponding FrameLabel is not visible)? The FrameLabel is there, when I export the plot to PDF, I can see a small part of it. I tried to play with FrameMargin as an option to the Overlay function, but that only adds white space. $\endgroup$
    – Skumin
    Mar 7, 2016 at 15:03
7
$\begingroup$

By the upper Mr. Jason B.'s nice codes on TwoAxisListPlot, I made one on DateListPlot as TwoAxisDateListPlot as following, some notations listed for helping others to change it to other ***Plot cases.

TwoAxisDateListPlot[{datelistLeft_?ListQ, dateListRight_?ListQ},opts : OptionsPattern[]] :=
    Module[ {shapedListRight, plotLeft, plotRight, twoRanges, result},

        (*check lists' depth*)
        If[ Or[ArrayDepth@datelistLeft != 2, ArrayDepth@dateListRight != 2],
            Return[$Failed]
        ];

        (* to be reshaped*)
        shapedListRight = dateListRight;

        (*find plots'Ranges*)
        {plotLeft, plotRight} = 
         DateListPlot /@ {datelistLeft, shapedListRight};
        twoRanges = 
         Last@Charting`get2DPlotRange@# & /@ {plotLeft, plotRight};

        (*reshape dataRight*)
        shapedListRight[[;; , 2]] = 
         Rescale[shapedListRight[[;; , 2]], Last@twoRanges, First@twoRanges];

        (*draw together*)
        result = DateListPlot[{datelistLeft, shapedListRight},
          Frame -> True, 
          FrameTicks -> {{Automatic, 
             Charting`FindTicks[First@twoRanges, 
              Last@twoRanges]}, {Automatic, Automatic}}, 
          FrameStyle -> {{ColorData[97][1], ColorData[97][2]}, {Automatic, 
             Automatic}}, FilterRules[{opts}, Options[DateListPlot]]];

        (*return shaped plots*)
        Return[result];
    ]
TwoAxisDateListPlot[datelistLeft_?ListQ, dateListRight_?ListQ, opts : OptionsPattern[]] := TwoAxisDateListPlot[{datelistLeft, dateListRight}, opts]

simple demos as :

list1 = FinancialData["NYSE:IBM", "March. 8, 2015"];
list2 = FinancialData["NASDAQ:AAPL", "March. 8, 2015"];

TwoAxisDateListPlot[list1, list2]

enter image description here

If some options given, it shows as this.

TwoAxisDateListPlot[list1, list2,
 DateTicksFormat -> {"MonthNameShort", ".", "Year"},
 FrameLabel -> {{Style["IBM", Larger, Bold], 
    Style["AAPL", Larger, Bold]}, {None, None}},
 PlotLabel -> Style["Stocks Comparsion", 18, Bold]
 ]

enter image description here

If PlotTheme be used, a new version comes up

 TwoAxisDateListPlot[{datelistLeft_?ListQ, dateListRight_?ListQ}, opts : OptionsPattern[]] :=
        Module[ {shapedListRight, plotLeft, plotRight, twoRanges, theme, colors, result},

           (*check lists' depth*)
            If[ Or[ArrayDepth@datelistLeft != 2, ArrayDepth@dateListRight != 2],
                Return[$Failed]
            ];

            (*get colors*)
            theme = Lookup[Association[opts], PlotTheme, Automatic];
            colors = 
             Most /@ PadRight[{}, {2}, 
               "DefaultPlotStyle" /. (Method /. 
                  Charting`ResolvePlotTheme[theme, DateListPlot])];

            (* to be reshaped*)
            shapedListRight = dateListRight;

            (*find plots'Ranges*)
            {plotLeft, plotRight} = 
             DateListPlot /@ {datelistLeft, shapedListRight};
            twoRanges = 
             Last@Charting`get2DPlotRange@# & /@ {plotLeft, plotRight};

            (*reshape dataRight*)
            shapedListRight[[;; , 2]] = 
             Rescale[shapedListRight[[;; , 2]], Last@twoRanges, First@twoRanges];

            (*draw together*)
            result = DateListPlot[{datelistLeft, shapedListRight},
              Frame -> True, 
              FrameTicks -> {{Automatic, 
                 Charting`FindTicks[First@twoRanges, 
                  Last@twoRanges]}, {Automatic, Automatic}},
              FrameStyle -> {colors, {Automatic, Automatic}}, 
              FilterRules[{opts}, Options[DateListPlot]]];

            (*return shaped plots*)
            Return[result];
        ]
    TwoAxisDateListPlot[datelistLeft_?ListQ, dateListRight_?ListQ, opts : OptionsPattern[]] := TwoAxisDateListPlot[{datelistLeft, dateListRight}, opts]

demos as

TwoAxisDateListPlot[list1, list2,
 DateTicksFormat -> {"MonthNameShort", ".", "Year"},
 FrameLabel -> {{Style["IBM", Larger, Bold], 
    Style["AAPL", Larger, Bold]}, {None, None}},
 PlotLabel -> Style["Stocks Comparsion", 18, Bold],
 PlotTheme -> "Marketing"
 ]

enter image description here

or

TwoAxisDateListPlot[list1, list2,
 DateTicksFormat -> {"MonthNameShort", ".", "Year"},
 FrameLabel -> {{Style["IBM", Larger, Bold], 
    Style["AAPL", Larger, Bold]}, {None, None}},
 PlotLabel -> Style["Stocks Comparsion", 18, Bold],
 PlotTheme -> "Business"
 ]

enter image description here

or

TwoAxisDateListPlot[list1, list2,
 DateTicksFormat -> {"MonthNameShort", ".", "Year"},
 FrameLabel -> {{Style["IBM", Larger, Bold], 
    Style["AAPL", Larger, Bold]}, {None, None}},
 PlotLabel -> Style["Stocks Comparsion", 18, Bold],
 PlotTheme -> "Detailed"
 ]

enter image description here

There's always one for using.

$\endgroup$
3
$\begingroup$

ArgentoSapiens's answer works well, but if the two plots don't have quite the same horizontal range, or you want to add different-sized labels to the two vertical axes, then it can be a bit tricky to line the two plots up correctly in the Overlay. I figured out the following trick that helped a lot with the alignment:

  1. Include both plots' frames and labels in each plot. E.g. set Frame -> {{True, True},{True,False}} in both plots, and add the exact same labels to both plots. This way all the spacing will be consistent between the two plots.

  2. Set each duplicated feature to be Transparent in one of the two plots (e.g. using FrameStyle). This way the elements will still take up the right amount of space, but when you overlay them, they won't be twice as dark as they should be.

Now when you combine the two plots using Overlay, they should be almost perfectly lined up, and you don't need to worry about setting the ImagePadding. (Although you still may need to tweak the individual plots with ImageSize, and/or the Overlay with the Alignment option, in order to line them up perfectly.)

Also, if you do it this way then the image will be cropped correctly, whereas there will be extra white space around the sides if you set ImagePadding too big.

$\endgroup$
3
$\begingroup$
ClearAll[TwoAxisDateListPlotV12]
Needs["Calendar`"];
TwoAxisDateListPlotV12[dat1__, dat2__, opts : OptionsPattern[]] := 
  Block[{data1 = dat1, data2 = dat2, plot1, plot2, userOptions, 
    defaultOptions, minx, maxx, temp},
   (*display two datelist-graphs on one diagram*)
   (*span x*)
   
   If[DateQ[First@data1["Dates"]] 
     (*find out date format*), 
     temp = SortBy[data1["Dates"]~Join~data2["Dates"], AbsoluteTime];
     minx = First@AbsoluteTime[#] & /@ temp["Dates"]; 
     maxx = Last@AbsoluteTime[#] & /@ temp["Dates"] - 1; 
     minx = Min[{AbsoluteTime[#] & /@ data1["Dates"], 
        AbsoluteTime[#] & /@ data2["Dates"]}];
     maxx = 
      Max[{AbsoluteTime[#] & /@ data1["Dates"], 
        AbsoluteTime[#] & /@ data2["Dates"]}];]
    (*get options*)
    
    userOptions = FilterRules[{opts}, Options[DateListPlot]];
   defaultOptions = 
    FilterRules[{PlotRange -> {{minx, maxx}, {All, All}}, 
      ImagePadding -> {{40, 40}, {25, 5}}}, Options[DateListPlot]];
   (*do the plots*)
   plot1 = DateListPlot[data1, PlotStyle -> Blue, 
      Frame -> {{True, False}, {True, False}}, 
      FrameStyle -> {Directive[FontFamily -> "Helvetica", Bold], 
        Directive[FontFamily -> "Helvetica", Bold, Blue], Automatic, 
        Automatic}, userOptions, defaultOptions] // Quiet;
   plot2 = 
    DateListPlot[data2, PlotStyle -> Darker[Green], Axes -> False, 
      Frame -> {{False, True}, {False, False}}, FrameTicks -> All, 
      FrameStyle -> {Automatic, Automatic, Automatic, 
        Directive[FontFamily -> "Helvetica", Bold, Darker[Green]]}, 
      userOptions, defaultOptions] // Quiet;
   Overlay[{plot1, plot2}]];

list1 = FinancialData["APPL", "Febuary 5, 2015"];
list2 = FinancialData["GOOGL", "March 5, 2015"];
TwoAxisDateListPlotV12[list1, list2, AspectRatio -> 0.3, 
 ImageSize -> Large]

enter image description here

$\endgroup$

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.