Take the 2-minute tour ×
Mathematica Stack Exchange is a question and answer site for users of Mathematica. It's 100% free, no registration required.

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}}]]
share|improve this question
2  
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 at 11:57

4 Answers 4

up vote 69 down vote accepted

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, None, None, All},
    FrameStyle -> {Automatic, Automatic, Automatic, Red}
]

Plot 2

Overlay[{plot1, plot2}]

Double-axis plot

Edit: Cleared up which axis is which using FrameStyle.

share|improve this answer
    
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
    
How about having both vertical axes on the same side? This would allow for three or more vertical axes... –  P. Fonseca Jan 24 '12 at 21:18
1  
@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
1  
@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

Even though this question has been flagged as answered, I think the answers are more complicated than they need to be (with respect). 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.

share|improve this answer

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

share|improve this answer

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

share|improve this answer
5  
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
1  
@J.M. no worries. Many thanks again ! –  500 Jan 25 '12 at 20:12

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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