1 Plot, 2 Scale/Axis

149

122

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

500

Posted 2012-01-24T17:15:26.537

Reputation: 5 169

6Come on, am I the only one who finds "2 scales, 1 plot" hilarious? – Aron – 2014-05-12T11:57:47.597

2

You'll find a lot of info with this search: https://groups.google.com/forum/#%21searchin/comp.soft-sys.math.mathematica/TwoAxisListPlot

– Szabolcs – 2012-01-24T17:20:07.523

@Szabolcs, Thank You I found the above bouncing from your link ! – 500 – 2012-01-24T17:33:58.160

You can start by replacing the appropriate line: {fgraph, ggraph} = MapIndexed[ListPlot[#, Axes -> True, Joined -> True, PlotStyle -> ColorData[1][#2[[1]]]] &, {f, g}];. – J. M.'s ennui – 2012-01-24T17:35:18.923

Ooh, this is an ancient one, I remember implementing my own version some 5 years before. – István Zachar – 2012-01-24T18:16:03.693

Answers

151

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.

ArgentoSapiens

Posted 2012-01-24T17:15:26.537

Reputation: 7 510

Note that previous versions of posts are available and there's a box where you can put a note about the changes. It's not necessary to put the note directly into the post.

– Szabolcs – 2012-01-24T18:53:29.790

2BTW +1 for using Overlay :-) I never managed to make good use of it. – Szabolcs – 2012-01-24T19:01:25.970

How about having both vertical axes on the same side? This would allow for three or more vertical axes... – P. Fonseca – 2012-01-24T21:18:40.570

2@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. – ArgentoSapiens – 2012-01-24T22:52:16.620

@ArgentoSapiens, Thank You very much. I will leave it open to see if some other experts come up with alternative but this definitely solved my problem ! – 500 – 2012-01-25T01:26:25.597

1

@ArgentoSapiens in my field, there are a lot of graphics organized like in the following schematics: http://i.imgur.com/h13bH.jpg.

– P. Fonseca – 2012-01-25T07:09:01.323

@BenjaminHodgson In V10 it works with PlotRange -> All and FrameTicks -> All – ybeltukov – 2015-11-17T00:44:47.037

2@BenjaminHodgson using FrameTicks -> All instead of the proposed solution solved it for me. – Valacar – 2017-01-23T09:11:10.673

@eldo has posted a nice solution using Overlay here and here.

– riddleculous – 2017-07-07T09:34:09.550

3Nice 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. – Howard Lovatt – 2018-02-20T07:06:11.120

Thanks @ArgentoSapiens . It was the ImagePadding function that I didn't know about, so you can imagine the machinations I was going through trying to get overlays to line up! – Bill N – 2019-01-15T12:53:41.623

5Setting PlotRange -> All or PlotRange -> Full breaks the numbering on the right-hand axis. Any idea why, and how to fix it? – Benjamin Hodgson – 2013-04-16T03:33:39.487

@poorsod, I suggest you post a new question with an example showing your problem. – ArgentoSapiens – 2013-04-16T14:23:23.360

35

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

J. M.'s ennui

Posted 2012-01-24T17:15:26.537

Reputation: 115 520

Is it possible to pass the range for each of the axis to the function? – RMMA – 2014-03-07T08:32:10.270

8If anybody's interested, I could modify the functions a bit to take options (e.g. nondefault colors for the two plots)... – J. M.'s ennui – 2012-01-25T03:45:12.683

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. – 500 – 2012-01-25T07:32:37.617

That would take a fair bit of effort. Would you mind a wait of a few days? – J. M.'s ennui – 2012-01-25T07:50:23.970

TwoAxisListPlot does not work on version 7, but TwoAxisListLinePlot does. Can you tell why? – Mr.Wizard – 2012-01-25T16:30:12.227

1@J.M. no worries. Many thanks again ! – 500 – 2012-01-25T20:12:20.227

@Mr.Wizard I don't quite know why; I don't have version seven to test it on. What exactly happens? – J. M.'s ennui – 2012-01-25T22:11:38.277

I see this: http://i.stack.imgur.com/Yp1Iw.png

– Mr.Wizard – 2012-01-25T22:29:55.360

@J.M., Thanks for the Edit ! – 500 – 2012-02-01T03:12:26.450

I still need to work on the version that allows for picking custom colors, @500, but that will take some more time, as I have other things to do... – J. M.'s ennui – 2012-02-01T03:22:42.193

did the more customizable version of this ever get finished? I'm looking for custom colors etc – BeauGeste – 2018-10-01T19:29:16.393

@Beau, no, I haven't yet found the time; maybe someday... – J. M.'s ennui – 2018-10-01T19:30:06.483

@Öskå, yes, I really should be looking into that, but I've been somewhat busy lately. I do promise to work on this in the near future. – J. M.'s ennui – 2013-06-20T14:28:19.293

27

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.

George Wolfe

Posted 2012-01-24T17:15:26.537

Reputation: 5 088

Thank you George. Which version of MMA that you used? – Nam Nguyen – 2020-10-15T09:46:13.133

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? – George Wolfe – 2020-11-16T18:25:51.490

17

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

The Quantum Physicist

Posted 2012-01-24T17:15:26.537

Reputation: 902

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. – SPIL – 2018-09-30T13:07:37.413

@SPIL sorry man. I haven't worked on Mathematica in a while. – The Quantum Physicist – 2018-09-30T14:21:05.827

Have you switched to using R instead then? – SPIL – 2018-09-30T15:07:06.567

@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. – The Quantum Physicist – 2018-09-30T16:15:34.030

@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? – Gvxfjørt – 2020-03-09T12:17:58.110

13

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

Jason B.

Posted 2012-01-24T17:15:26.537

Reputation: 58 546

1Superb! This should be a Mathematica builtin function! – grbl – 2017-02-14T20:22:33.467

1

@grbl - Thanks! You should take a second and send them a message, http://www.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.

– Jason B. – 2017-02-14T20:47:36.567

1It's been requested by many users since the 90s – Mike Honeychurch – 2017-04-26T00:22:05.990

13

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

Peter Breitfeld

Posted 2012-01-24T17:15:26.537

Reputation: 4 892

11

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

Hargrot

Posted 2012-01-24T17:15:26.537

Reputation: 153

What is DateQ? It seems not to a buit-in. – iav – 2015-07-30T11:40:05.593

3@iav It is loaded by Needs["Calendar`"] – Mr.Wizard – 2015-08-04T06:50:31.400

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. – Skumin – 2016-03-07T15:03:19.797

4

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.

Jerry

Posted 2012-01-24T17:15:26.537

Reputation: 2 272

3

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.

tparker

Posted 2012-01-24T17:15:26.537

Reputation: 1 672

1

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)

Lukas Lang

Posted 2012-01-24T17:15:26.537

Reputation: 17 767

0

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

Steffen Jaeschke

Posted 2012-01-24T17:15:26.537

Reputation: 3 169