Plot same data set on two different y axis scales

NOTE: Question has been updated.
Hello all,
I want to plot a matrix (37 x 10) represented by sum_ET10 with 2 different y axis scales; km^3/year (original unit) on y axis lhs & mm/year (new unit) on y axis rhs. My code is shown below; I have also included an image below. Currently, my graph is still incorrect. What I want to do is to have a single plot as opposed to the two plots that I'm getting
%% Getting a 37 x 10 matrix of sum_ET10 & sum_area
decade = 10;
sum_area = squeeze(sum(reshape(area,size(area,1),decade,[]),2)/10);
sum_ET10 = squeeze(sum(reshape(ET,size(ET,1),decade,[]),2)/10);
% Plot the results
x_decade = 1:10;
f1 = figure(1);
x1 = axes;
plot(x_decade,sum_ET10(1,:),'-ok');
% Query the YTicks
yt = get(x1,'YTick');
% Create new axis based on existing axis
x2 = copyobj(x1,f1);
% Set new axis transparent
set(x2,'Color','none')
% Remove XTicks
set(x2,'Xtick',[])
% Display the YTicks on the right side
set(x2,'YAxisLocation','right')
% Converting values to mm/year
mm_sum_ET10 = yt/2199000*1000000;
% Update labels
set(x2,'YTickLabel',mm_sum_ET10)
grid on;
xlabel(x1,'Decade');
ylabel(x1,'km^3/year');
ylabel(x1,'mm/year');
untitled.jpg
Any help is appreciated. This is my first time doing different scaled axes, so I'm in need of help.
Thank you.

1 comentario

Adam Danz
Adam Danz el 5 de Feb. de 2020
Editada: Adam Danz el 5 de Feb. de 2020
Regarding the error, look at the size of sum_area and the size of yt. The ./ notation means that your dividing element i of the first variable by element i of the 2nd variable. That requires both variables having the same number of elements.
Update following your update
You need to copy the axis before plotting the line. But still, this is a bad solution. use yyaxis.

Iniciar sesión para comentar.

 Respuesta aceptada

Adam Danz
Adam Danz el 5 de Feb. de 2020
Editada: Adam Danz el 5 de Feb. de 2020
You should be using yyaxis instead of overlaying a 2nd axes which can lead to all sorts of problems.
Demo:
figure()
yyaxis left
plot(rand(1,20)*1000);
yyaxis right
set(gca, 'ytick', 0:10:100, 'ylim', [0,100], 'Ycolor', 'k')
See the link I provided for examples of yyaxis plots.
update
Applying that to your code would look something like this. The important part is to make sure the y limits of both y axes are set so that ylim(axis1) and ylim(axis2) are merely a conversion of each other. See the two lines below with the tag #important where you should make sure you're scaling the axes correctly.
% Plot the results
figure();
yyaxis left
plot(x_decade,sum_ET10(1,:),'-ok');
set(gca, 'YLim', [min(sum_ET10(1,:)), max(sum_ET10(1,:))]) % #important
yyaxis right
% Converting values to mm/year
mm_sum_ET10 = yt/2199000*1000000; % I assume yt is a vector
set(gca,'YTick',mm_sum_ET10, 'YLim', [min(mm_sum_ET10), max(mm_sum_ET10)]) % #important
ylabel('mm/year');
% go back to left axes (main axes)
yyaxis left
grid on;
xlabel('Decade');
ylabel('km^3/year');

10 comentarios

Hi @Adam Danz, I want to have a single plot with two separate units, i.e. km^3/year on y axis left & mm/year on y axis right. Using yyaxis would give me 2 plots instead of 1.
Adam Danz
Adam Danz el 5 de Feb. de 2020
Editada: Adam Danz el 5 de Feb. de 2020
Do you see two plots in the demo i provided? No. yyaxis merely controls which vertical axis, left or right, you're working with. If you're having trouble implementing the solution show me the code and i can help straighten it out.
@Adam Danz, I implemented your code with an additional line below; and am getting the figure below; How do I get the y values on the right axis to be at the same position as the left axis values?
yt = get(gca, 'YTick'); % after yyaxis right
Adam Danz
Adam Danz el 6 de Feb. de 2020
Editada: Adam Danz el 6 de Feb. de 2020
Looking better! Set the ytick and ylim properties correctly. See the 2nd #important tag I referred to. Insert the correct values there.
I don't have access to your variables so I can only guess at what's going on. The idea is that the y ticks of the 2nd axis should be a direct conversion of the y ticks of the first axis. Likewise, the y limit of the 2nd axis should be a direct conversion of the y limit of the first axis. There's no need to use YTickLabel since your tick labels are numeric.
It would look something like this
yyaxis left
ax1 = gca();
yt = get(ax1,'YTick');
yl = ylim(ax1);
% convert
ytConverted = yt/2199000*1000000;
ylConverted = yl/2199000*1000000;
yyaxis right
set(gca,'YTick',ytConverted, 'YLim', ylConverted])
juan pedrosa
juan pedrosa el 6 de Mzo. de 2021
Editada: juan pedrosa el 6 de Mzo. de 2021
Hi, this answer assumes a metric correlation between the scales. How would you approach two scales with no correlation?
Adam Danz
Adam Danz el 6 de Mzo. de 2021
@juan pedrosa the question is how to "plot [the] same data set on two different y axis scales". That would imply a correlation. If the two sets of data do not correlate, I don't understand what the goal would be.
juan pedrosa
juan pedrosa el 7 de Mzo. de 2021
Editada: juan pedrosa el 7 de Mzo. de 2021
I'm not trying to say that your answer is somehow wrong, I'm not a native english speaker, maybe it sounded rude.
Let's say we have a time series with three variables date,price and volume. You could plot the date as X, and the price as Y, but the volume has no metric (as in the measure unit) correlation with the price, how could you equate the values to be proportionals of each other?
Adam Danz
Adam Danz el 7 de Mzo. de 2021
Editada: Adam Danz el 7 de Mzo. de 2021
No worries, @juan pedrosa, I admire your 2nd language abilities. I just wanted to be clear why it's necessary that the two sets of y-data must be on the same scale for this question.
The example in your previous comment gives more context. It sounds like you just need to set the ylim for the left/right axes.
Alternatively, you could scale the volume data so its range is the same as the price data. That means the lowest and highest prices correlate to the lowest and highest volumes.
Let's say that price ranges from 0-100 and the price data are all within this range, even if none of the prices equal 0 or 100 (ie, price=[20 50 55 80 95]). But, the volume data has a different range, say 500 to 1000 while the volume values are volume=[510 560 620 780 950]. You have to 1) rescale the volume data to the price-range (0:100) and 2) then scale the ytick labels back to the volume range (500:1000).
Demo:
time = 1:5;
priceBounds = [0,100];
price = [20 50 55 80 95];
volumeBounds = [500,1000];
volume = [510 560 620 780 950];
% scale volume data to the range or price data
volumeRescaled = (volume-volumeBounds(1)) / range(volumeBounds) * range(priceBounds) + priceBounds(1);
clf()
yyaxis('left');
plot(time, price)
ylim(priceBounds)
yticks = linspace(priceBounds(1),priceBounds(2),11);
set(gca,'ylim',priceBounds,'ytick', yticks)
ylabel('price ($)')
yyaxis('right');
plot(time, volumeRescaled)
set(gca,'ylim',priceBounds,'ytick', yticks) % same ticks and lim as left axis!
ylabel('volume (a.u.)')
% now you have to rescale the right yticks to set the correct tick labels
% Note the similarity with to the volumeRescale above
ytickRight = (yticks-priceBounds(1)) / range(priceBounds) * range(volumeBounds) + volumeBounds(1);
set(gca, 'YTickLabel', ytickRight)
Note that this is the same as just using the raw data and setting ylim, which is much easier and cleaner.
time = 1:5;
priceBounds = [0,100];
price = [20 50 55 80 95];
volumeBounds = [500,1000];
volume = [510 560 620 780 950];
clf()
yyaxis('left');
plot(time, price)
ylim(priceBounds)
set(gca,'ylim',priceBounds)
ylabel('price ($)')
yyaxis('right');
plot(time, volume)
set(gca,'ylim',volumeBounds)
ylabel('volume (a.u.)')
great answer! thank you.
Nice! Thanks!

Iniciar sesión para comentar.

Más respuestas (0)

Productos

Versión

R2018b

Preguntada:

el 5 de Feb. de 2020

Comentada:

el 6 de Abr. de 2022

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!

Translated by