1 Plot, 2 Scale/Axis

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

-
You'll find a lot of info with this search: groups.google.com/forum/#!searchin/… – Szabolcs Jan 24 '12 at 17:20
@Szabolcs, Thank You I found the above bouncing from your link ! – 500 Jan 24 '12 at 17:33
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. Jan 24 '12 at 17:35
Ooh, this is an ancient one, I remember implementing my own version some 5 years before. – István Zachar Jan 24 '12 at 18:16
Come on, am I the only one who finds "2 scales, 1 plot" hilarious? – Aron May 12 '14 at 11:57

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,
Frame -> {True, True, True, False},
FrameStyle -> {Automatic, Blue, Automatic, Automatic}
]


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


Overlay[{plot1, plot2}]


Edit: Cleared up which axis is which using FrameStyle.

-
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 Jan 24 '12 at 18:53
BTW +1 for using Overlay :-) I never managed to make good use of it. – Szabolcs Jan 24 '12 at 19:01
@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 Jan 24 '12 at 22:52
@ArgentoSapiens in my field, there are a lot of graphics organized like in the following schematics: i.imgur.com/h13bH.jpg. – P. Fonseca Jan 25 '12 at 7:09
Setting PlotRange -> All or PlotRange -> Full breaks the numbering on the right-hand axis. Any idea why, and how to fix it? – Benjamin Hodgson Apr 16 '13 at 3:33

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


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;


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.

-

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


-

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]


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

-
What is DateQ? It seems not to a buit-in. – iav Jul 30 at 11:40
@iav It is loaded by Needs["Calendar"] – Mr.Wizard Aug 4 at 6:50

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
]


-

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


-
If anybody's interested, I could modify the functions a bit to take options (e.g. nondefault colors for the two plots)... – J. M. Jan 25 '12 at 3:45
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 Jan 25 '12 at 7:32
That would take a fair bit of effort. Would you mind a wait of a few days? – J. M. Jan 25 '12 at 7:50
TwoAxisListPlot does not work on version 7, but TwoAxisListLinePlot does. Can you tell why? – Mr.Wizard Jan 25 '12 at 16:30
@J.M. no worries. Many thanks again ! – 500 Jan 25 '12 at 20:12