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
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 68 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
    
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

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

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

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

This site is currently not accepting new answers.

Not the answer you're looking for? Browse other questions tagged .