Using 3 "y" axes for multiple plot

15 views (last 30 days)
LUCAS
LUCAS on 28 Jan 2025
Commented: LUCAS on 21 Feb 2025 at 12:31
Hello,
I am working with multiple plots in MATLAB and I would like to use three different "y" axis for the different axes within a single figure. I have no problem using two "y" axes with yyaxis, I can't include that function in my for loop (this loop reads the data from each column to be plotted from the Excel file). I read about a function called addaxis, but I don't know how to use it.
Also, I would like the plots to have different colors for each "y" axis, since MATLAB defaults to red for Y1 and blue for Y2. Any ideas on how to achieve this?
Any suggestions would be greatly appreciated!
Best Regards!
Lucas.
clc;
clear;
nombre_excel = 'Hoja_fuente.xlsx';
datos = readtable (nombre_excel);
Error using readtable (line 517)
Unable to find or open 'Hoja_fuente.xlsx'. Check the path and filename or file permissions.
encabezados = datos.Properties.VariableNames(2:end);
encabezados = strrep(encabezados, '_', ' ');
t = datetime(datos.Tiempo,'ConvertFrom', 'datenum', 'Format', 'HH:mm:ss'); %Si da probemas: sustituir 'datenum' por 'excel'
numero_columnas=size(datos,2) - 1;
fig = figure('Name','Representación interactiva MATLAB', 'NumberTitle','off', 'Color', 'w');
hold on;
grid on;
for i=2:numero_columnas+1
y_i = datos(:,i);
y_i = table2array(y_i);
if max(y_i) <= 100
yyaxis right
plot(t, y_i, 'LineWidth', 1.5, 'DisplayName', encabezados{i-1}, SeriesIndex = 1, marker='.', markersize = 1, color = 'r');
end
if max(y_i) > 100
yyaxis left
plot(t, y_i, 'LineWidth', 1.5, 'DisplayName', encabezados{i-1}, SeriesIndex = 1, marker='.', markersize = 1, color = 'b'); %['Y_' num2str(i-1)]
end
end
title('Gráfica Interactiva');
legend('show');
xlabel('Tiempo( hh:mm:ss )', 'FontSize', 12);
%ylabel(encabezados, 'Rotation', 0, 'Color', 'b');
ax=gca;
ax.XAxis.Exponent = 0;
ax.XAxis.TickLabelFormat = 'HH:mm:ss';
axis tight;
ax.XAxis.SecondaryLabelFormatMode = 'manual';
set(gca, 'Position', [0.056770833333333,0.157667386609071,0.894270833333333,0.809935205183586]);
legend('Location', 'southoutside', 'NumColumns', 6, 'Orientation', 'horizontal', 'NumColumnsMode','manual', 'Interpreter','none', 'FontSize', 8, 'FontWeight', 'bold', 'FontName', 'Arial Narrow', 'box', 'on');
set(legend, 'IconColumnWidth', 15, 'Position', [0.004678527128273,0.041036717062635,0.988802104021113,0.058815920456996]);
format long g;
This code is working but It can only plot 2 "y" axes; but if I try the addaxis in order to implement the third "y" axis, my code It´s not working:
clc;
clear;
nombre_excel = 'Hoja_fuente.xlsx';
datos = readtable (nombre_excel);
encabezados = datos.Properties.VariableNames(2:end);
encabezados = strrep(encabezados, '_', ' ');
t = datetime(datos.Tiempo,'ConvertFrom', 'datenum', 'Format', 'HH:mm:ss'); %Si da probemas: sustituir 'datenum' por 'excel'
numero_columnas=size(datos,2) - 1;
fig = figure('Name','Representación interactiva MATLAB DQA', 'NumberTitle','off', 'Color', 'w'); %Preguntar si NumberTitle on o off
hold on;
grid on;
for i=2:numero_columnas+1
y_i = datos(:,i);
y_i = table2array(y_i);
if max(y_i) <= 20
addaxis(t, y_i, [0 20],'LineWidth',1.3,'Color','b')
plot(t, y_i, 'LineWidth', 1.5, 'DisplayName', encabezados{i-1}, 'SeriesIndex', 1, 'Marker', '.', 'MarkerSize', 1, 'Color', 'green');
end
if 20 < max(y_i) && max(y_i) <= 100
addaxis(t, y_i, [0 100], 'LineWidth',1.3,'Color','r')
plot(t, y_i, 'LineWidth', 1.5, 'DisplayName', encabezados{i-1}, SeriesIndex = 1, marker='.', markersize = 1, color = 'red'); %['Y_' num2str(i-1)]
end
if max(y_i) > 100
addaxis(t, y_i, [0 max(y_i)],'LineWidth',1.3,'Color','g')
plot(t, y_i, 'LineWidth', 1.5, 'DisplayName', encabezados{i-1}, SeriesIndex = 1, marker='.', markersize = 1, color = 'b'); %['Y_' num2str(i-1)]
end
end
title('Gráfica Interactiva DiagnóstiQA');
legend('show');
xlabel('Tiempo( hh:mm:ss )', 'FontSize', 12);
%ylabel(encabezados, 'Rotation', 0, 'Color', 'b');
ax=gca;
ax.XAxis.Exponent = 0;
ax.XAxis.TickLabelFormat = 'HH:mm:ss'; %QUITAR ESTA LINEA DE CODIGO SI PREFERIMOS FORMATO TEMPORAL mm:ss
axis tight; %INSTRUCCIONES: tight, tickaligned o padded %en vez de axis puedo usar xlim o ylim si solo quiero ajustar 1 de los ejes
ax.XAxis.SecondaryLabelFormatMode = 'manual'; %ESTO SOLUCIONA EL 31 -1!
set(gca, 'Position', [0.056770833333333,0.157667386609071,0.894270833333333,0.809935205183586]); %El segundo numero es el margen desde el borde inferior de la ventana y el cuarto número es la altura de los ejes
legend('Location', 'southoutside', 'NumColumns', 6, 'Orientation', 'horizontal', 'NumColumnsMode','manual', 'Interpreter','none', 'FontSize', 8, 'FontWeight', 'bold', 'FontName', 'Arial Narrow', 'box', 'on');
set(legend, 'IconColumnWidth', 15, 'Position', [0.004678527128273,0.041036717062635,0.988802104021113,0.058815920456996]);
format long g;
  2 Comments
dpb
dpb on 28 Jan 2025
Edited: dpb on 29 Jan 2025
...
for i=2:numero_columnas+1
y_i = datos(:,i);
y_i = table2array(y_i);
if max(y_i) <= 20
addaxis(t, y_i, [0 20],'LineWidth',1.3,'Color','b')
plot(t, y_i, 'LineWidth', 1.5, 'DisplayName', encabezados{i-1}, 'SeriesIndex', 1, 'Marker', '.', 'MarkerSize', 1, 'Color', 'green');
end
...
Every time you call addaxis it will create another one so you'll end up with as many as there are columns by using it inside a loop. To have only three total you would need to follow the idea I showed below of collecting all the columns of each of the three sizes via a logical addressing vector of columns and plot each of those in one call. The simple binary of isbig() and ~isbig() won't work here because of more than two states, but it would be simple enough to build the array for each group...
BKPTS=[20 100];
isSmall =all(ttD{:,:}<=BKPTS(1));
isMedium=all(ttD{:,:}>BKPTS(1) & ttD{:,:}<=BKPTS(2));
isLarge =all(ttD{:,:}>BKPTS(2));
where I reverted again to the use of the timetable because it will let you address only the numeric variables without the time...
dpb
dpb on 28 Jan 2025
I had an earlier comment that seems to have gotten lost -- in it I suggested an easier alternative for specifically three y axes would be the FEX submission <plotyyy>. It isn't quite as flexible, but it is somewhat simpler interface as well. You will still need to pass the three sets as arrays, however, rather than looping to make it work as you wish.

Sign in to comment.

Accepted Answer

dpb
dpb on 28 Jan 2025
ombre_excel = 'Hoja_fuente.xlsx';
datos = readtable (nombre_excel);
datos.Properties.VariableNames=strrep(datos.Properties.VariableNames,'_',' '); % rename the variables in the table
datos.Tiempo=datetime(datos.Tiempo,'ConvertFrom', 'datenum', 'Format', 'HH:mm:ss'); % convert in the table itself
ttD=table2timetable(datos); % convert to timetable
numero_columnas=width(datos)-1; % width instead of size(x,2)
fig = figure('Name','Representación interactiva MATLAB', 'NumberTitle','off', 'Color', 'w');
hold on;
grid on;
BIG=100; % the logic size value as variable, not magic number in code so can change
isbig=any(max(ttD{:,:})>BIG); % logic vector of which are the big columns
yyaxis right
plot(ttD.Tiempo,ttD{:,isbig}),'.-r','LineWidth',1.5,'markersize',1); % plot the big uns...
yyaxis left
plot(ttD.Tiempo,ttD{:,~isbig}),'.-b','LineWidth',1.5,'markersize',1); % then the little guys...
title('Gráfica Interactiva');
xlabel('Tiempo( hh:mm:ss )', 'FontSize', 12);
ax=gca;
ax.XAxis.Exponent = 0;
ax.XAxis.TickLabelFormat = 'HH:mm:ss';
axis tight;
ax.XAxis.SecondaryLabelFormatMode = 'manual';
set(gca, 'Position', [0.056770833333333,0.157667386609071,0.894270833333333,0.809935205183586]);
displaynames=[ttD.Properties.VariableNames(isbig) ttd.Properties.VariableNames(~isbig)]; % put names in order plotted for legend
hLg=legend(displaynames,'Location', 'southoutside', 'NumColumns', 6, 'Orientation', 'horizontal', 'NumColumnsMode','manual', 'Interpreter','none', 'FontSize', 8, 'FontWeight', 'bold', 'FontName', 'Arial Narrow', 'box', 'on');
set(hLg, 'IconColumnWidth', 15, 'Position', [0.004678527128273,0.041036717062635,0.988802104021113,0.058815920456996]);
Would shorten the code by using MATLAB array indexing by logical condition on which columns match the given condition. The conversion to the timetable is convenient because then the X time variable isn't considered part of the table data so the logical addressing vector length matches automagically the number of numeric variables in the table. Likewise with the VariableNames property, instead of including the time, it has only the data in the timetable so it also matches and then can select for the legend by the order in which the plots were created using the same logical indexing in the same order.
  1 Comment
LUCAS
LUCAS on 21 Feb 2025 at 12:31
Hi dear dpb,
Thanks for your answer/reply; I have seen it a few days ago.
I finally managed to get the 3 "y" axes, but it's not working as I expected. One possible solution to this problem could be creating an app with AppDesigner. This way, we can add as many "y" axes as we want.
If anyone is interested in seeing my App, just let me know, and I'll send it.
Thank you so much for your help, dear dpb. It has been very useful to me.
Best regards, Lucas Collado.

Sign in to comment.

More Answers (0)

Tags

Products


Release

R2024b

Community Treasure Hunt

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

Start Hunting!