4
$\begingroup$

I learned about how to plot two datasets in a single plot with two y-axes by using Overlay as has been done in one of the answers in this question.

Now, my datasets are not just positive but the second one also has negative y-values. As a consequence, the origins of the y-axes are now misaligned in the final plot (they are not at the same height).

Is it possible to use this method but align the origins of the different y-axes correspondingly?

I tried to use AxesOrigin but it doesn't seem to work.

Thank you for your help!

[Edit]

Minimal working example to illustrate my problem

plot1 = ListLinePlot[Accumulate[RandomReal[{0, 1}, {100}]], 
   PlotStyle -> Blue, ImagePadding -> 30, 
   Frame -> {True, True, True, False}, 
   FrameStyle -> {Automatic, Blue, Automatic, Automatic}];
plot2 = ListLinePlot[RandomReal[{-5, 40}, {100}], PlotStyle -> Red, 
   ImagePadding -> 30, Axes -> False, 
   Frame -> {False, False, False, True}, 
   FrameTicks -> {{None, All}, {None, None}}, 
   FrameStyle -> {Automatic, Automatic, Automatic, Red}];
Overlay[{plot1, plot2}]

enter image description here

Reading out the PlotRange might be a way.

$\endgroup$
  • 2
    $\begingroup$ For an user with your reputation, you should know by now to include a minimal working example that shows your code and problem. Please edit your question to improve it. It's never too late to get you Informed badge by taking the tour and learning about good questions. $\endgroup$ – rhermans Jul 17 at 12:36
  • 3
    $\begingroup$ You are right. I apologise for my sloppiness. I just edited my OP. $\endgroup$ – Display Name Jul 17 at 13:00
2
$\begingroup$

Not a complete answer, but some thought for you to start. If I undetstood you correctly, you want to align "zero" ticks of both axes. If so, you need to Show both plots with the same vertical range, and then Overlay new plots.

One can get PlotRanges by pr1=PlotRange[plot1] (and similarly for plot2). You also need PlotRangePadding with the command pad=Options[plot1,PlotRangePadding]. Next you compute common PlotRange by smth like cpr=MinMax[Join[pr1[[2]], pr2[[2]]]]. Now you are ready to replot both polts with this new cpr: newplot1=Show[plot1,PlotRange->cpr,PlotRangePadding->pad] and the like for the plot2. And finally Overlay[{newplot1,newplot2}].

enter image description here

You also may use undocumented command

Charting`get2DPlotRange[plot1]

This will give you "whole" PlotRange including PlotRangePadding. in this case in newplot1 you should use PlotRangePadding->None because it is already included in plotrange.

EDIT

Another idea. First you get "whole" PlotRange. Then you need to find such range (for the left axis, e.g.), so that after rescaling its zero becomes zero on the right axis:

Solve[Rescale[0,{x,pr1[[2,2]]},pr2[[2]]]==0,x]

Now you Show[plot1, PlotRange->{x,pr1[[2,2]]},PlotRangePadding->None], then Overlay[...].

enter image description here

$\endgroup$
  • $\begingroup$ You correctly understood my intention. However, in the actual example the ranges of the different y-axes are quite different (different regimes in terms of magnitudes). The problem is that one then also has to rescale one of the axes I'm afraid. It is a pity that this whole task is so tedious with MMA. Thanks for your answer anyway. $\endgroup$ – Display Name Jul 17 at 14:18
  • $\begingroup$ Great that works perfectly well. Thank you for the help :) $\endgroup$ – Display Name Jul 17 at 18:18
2
$\begingroup$

An alternative approach based on (1) Rescaleing the second data set to the range of first data set so that the two data sets are aligned at the desired point, (2) Using Charting`FindTicks to find the appropriate frame ticks for the right axis.

We need a simple helper function to find the second argument for Rescale:

ClearAll[modifiedrange]
modifiedrange[{{a_, b_}, {c_, d_}}, z_: 0] /; z <= d := {(a d - (a - b + d) z)/(b - z), d}

Examples:

SeedRandom[1]
data1 = Accumulate[RandomReal[{0, 1}, {100}]];
data2 = RandomReal[{-5, 40}, {100}];

ao = {0, 0};
data2b = Rescale[data2, modifiedrange[MinMax /@ {data1, data2}, ao[[2]]], MinMax @ data1]
tickF = Charting`FindTicks[MinMax@data1, modifiedrange[MinMax/@{data1, data2}, ao[[2]]]];

ListLinePlot[{data1, data2b}, 
  PlotStyle -> {Blue, Red}, Frame -> True, 
  FrameStyle -> {{Blue, Red}, {Automatic, Automatic}}, 
  FrameTicks -> {{Automatic, tickF}, {Automatic, Automatic}},
  AxesOrigin -> ao]

enter image description here

Use ao = {0, 10} to align the left and right axes at 10:

enter image description here

$\endgroup$
  • $\begingroup$ Thank you for your answer! $\endgroup$ – Display Name Jul 19 at 8:49

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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