Multiple X axis in different scale, but one y axis

Hello,
How to Add Multiple X axis in different scale? Please help me? It will look like this:

 Accepted Answer

Matlab does not support mutliple x axes other than the axes at the upper and lower borders of the plot.
One way to include multiple axis units is to create multi-lined x-axis ticks. The upper axis will be your main axis used to plot your data. Then define the axis limits for all additional pseudo-axes and compute the tick values for each pseudo-axis so they align with the x-ticks on the main axis. Use those value to create the multi-lined x-tick labels.
Follow the demo below and adjust it to fit your needs.
Demo
% Set up main axis (on top)
clf()
ax = axes();
ax.XTick = 0:200:2800;
ax.XLim = [0,2800];
% Set axis limits for all other axes
additionalAxisLimits = [...
0, 1400; % axis 2
19.2, 23.4; % axis 3
0.2, 3]; % axis 4
% Compute tick values for each axis to align with main axis
additionalAxisTicks = arrayfun(@(i){linspace(additionalAxisLimits(i,1), ...
additionalAxisLimits(i,2),numel(ax.XTick))}, 1:size(additionalAxisLimits,1));
% Set up multi-line ticks
allTicks = [ax.XTick; cell2mat(additionalAxisTicks')];
tickLabels = compose('%4d\\newline%4d\\newline%.1f\\newline%.1f', allTicks(:).');
% The %4d adds space to the left so the labels are centered.
% You'll need to add "%.1f\\newline" for each row of labels (change formatting as needed).
% Alternatively, you can use the flexible line below that works with any number
% of rows but uses the same formatting for all rows.
% tickLabels = compose(repmat('%.2f\\newline',1,size(allTicks,1)), allTicks(:).');
% Decrease axis height & width to make room for labels
ax.Position(3:4) = ax.Position(3:4) * .75; % Reduced to 75%
ax.Position(2) = ax.Position(2) + .2; % move up
% Add x tick labels
set(ax, 'XTickLabel', tickLabels, 'TickDir', 'out', 'XTickLabelRotation', 0)
% Define each row of labels
ax2 = axes('Position',[sum(ax.Position([1,3]))*1.08, ax.Position(2), .02, 0.001]);
linkprop([ax,ax2],{'TickDir','FontSize'});
axisLabels = {'Distance (t)','Area (m^2)','Cnt from 0 (m)','KB (m)'}; % one for each x-axis
set(ax2,'XTick',0.5,'XLim',[0,1],'XTickLabelRotation',0, 'XTickLabel', strjoin(axisLabels,'\\newline'))
ax2.TickLength(1) = 0.2; % adjust as needed to align ticks between the two axes
Similar examples in the forum

34 Comments

% Set up main axis (on top)
ax = axes();
ax.XTick = 4000:5000:30000; %Disp
ax.XLim = [4000,30000];
% Set axis limits for all other axes
additionalAxisLimits = [...
3500, 4500; % axis 2 WPA
0,6; % axis 3 KB
20,30; % axis 4 LCB
30,50; %axis 5 TPC
200, 500; %axis 6 MCTC
0, 50; %axis 7 BMt
100,1500; %axis 8 BMl
20, 250; %axis 9 AM
0, 1; %axis 10 CB
0, 1; %axis 11 CM
0, 1; %axis 12 CP
0, 1; %axis 13 CWP
0, 1]; %axis 14 CVP
Output: :( Help me plz :( :(
I can't see what's wrong without seeing your code.
My guess is that you forgot this transpose,
tickLabels = compose('%4d\\newline%4d\\newline%.1f\\newline%.1f', allTicks(:).');
% ---> ---> ---> ---> ---> ---> ---> ---> ---> ---> ---> ---> ^^
If that's not the problem go through your code line by line and compare the results to my version to see where it starts to differ.
I am in problem, I have 14 scale in X axis. but, only shows 4!!!
Again, same comment as above.
I can't help without seeing your code. The code you provided in a comment above is incomplete.
Share the relevant section of code.
% Set up main axis (on top)
ax = axes();
ax.XTick = 4000:5000:30000; %Disp
ax.XLim = [4000,30000];
% Set axis limits for all other axes
additionalAxisLimits = [...
3500, 4500; % axis 2 WPA
0,6; % axis 3 KB
20,30; % axis 4 LCB
30,50; %axis 5 TPC
200, 500; %axis 6 MCTC
0, 50; %axis 7 BMt
100,1500; %axis 8 BMl
20, 250; %axis 9 AM
0, 1; %axis 10 CB
0, 1; %axis 11 CM
0, 1; %axis 12 CP
0, 1; %axis 13 CWP
0, 1]; %axis 14 CVP
% Compute tick values for each axis to align with main axis
additionalAxisTicks = arrayfun(@(i){linspace(additionalAxisLimits(i,1), ...
additionalAxisLimits(i,2),numel(ax.XTick))}, 1:size(additionalAxisLimits,1));
% Set up multi-line ticks
allTicks = [ax.XTick; cell2mat(additionalAxisTicks')];
tickLabels = compose('%14d\\newline%14d\\newline%.1f\\newline%.1f', allTicks(:).');
% The %4d adds space to the left so the labels are centered.
% Decrease axis height & width to make room for labels
ax.Position(3:4) = ax.Position(3:4) * .75; % Reduced to 75%
ax.Position(2) = ax.Position(2) + .2; % move up
% Add x tick labels
set(ax, 'XTickLabel', tickLabels, 'TickDir', 'out')
% Define each row of labels
ax2 = axes('Position',[sum(ax.Position([1,3]))*1.1, ax.Position(2), .02, 0]);
linkprop([ax,ax2],{'TickDir','TickLength','FontSize'})
axisLabels = {'Distance (t)','Area (m^2)','Cnt from 0 (m)','KB (m)'}; % one for each x-axis
set(ax2,'XTick',0.5,'XLim',[0,1],'XTickLabel', strjoin(axisLabels,'\\newline'))
Here it is.
Output:
I see your mistake. You didn't expand the compose() function beyond the 4 rows I have in my demo. It's very important that you go through each line of code to understand what it does so you can learn something and so you can own your work and call it yours.
I've updated my answer to show how to flexibly create the compose() line no matter how many rows are in the tick labels. There are several small changes to my answer that you should look for but here's are the 3 main changes you need to make to your code.
1) replace the old compose() line with this one.
tickLabels = compose(repmat('%.2f\\newline',1,size(allTicks,1)), allTicks(:).');
Note that all of your labels will now have 2 dp.
2) Since you have so many rows of labels, you'll need to shrink the height of your axes even further.
% Decrease axis height & width to make room for labels
ax.Position(3) = ax.Position(3) * .75; % Reduced width to 75%
ax.Position(4) = ax.Position(4) * .40; % Reduced height to 40%
ax.Position(2) = ax.Position(2) + .48; % move up
3) Fill in the rest of the axis labels (see axisLabels variable).
By the way, if those axis limits are your real data, you could remove the last 4 rows since they are the same scale. That gives you more space for the plot.
Wow, it works. And at the last moment one last question, How can I get the lines, I mean the graph.
Where, I have to put, grid on?
I have tables, I have values of X and Y axis
How can I put those?
You help me a lot. Please,help me to plot. Whithout this, It will valueless. :(
The grid command places the vertical and horiztonal grid lines on the axes.
To plot the data, use the plot command. The x-values should be in the same units as your main axes on top (ranging from 4000 to 30000).
If you have trouble plotting, you may want to go through the Matlab Onramp to learn the basics.
I am a newbie in MATLab. I simply plot (x,y). But here, 14 different scale. So I cannot get it. Can you give me some idea for it? I would be greatfull.
one more thing. In your demo code, how can I change the value of y axis?
Please, don't leave me alone. I am at the last stage.
I am waiting ........ :( Without this, whole thing will be useless :( :(
% Set up main axis (on top)
ax = axes();
ax.XTick = 4000:5000:30000; %Disp
ax.XLim = [4000,30000];
% Set axis limits for all other axes
additionalAxisLimits = [...
3500, 4500; % axis 2 WPA
0,6; % axis 3 KB
20,30; % axis 4 LCB
30,50; %axis 5 TPC
200, 500; %axis 6 MCTC
0, 50; %axis 7 BMt
100,1500; %axis 8 BMl
20, 250; %axis 9 AM
0, 1;] %axis 10 CB
grid on
draft_y = [2, 4, 6, 8];
%
dispS = [4338.433882, 12602.51994, 20397.27172, 29240.4964];
% dispW = [4338.433882, 12602.51994, 20397.27172, 29240.49644];
% %bmT = [49.934497, 18.50834124, 11.99581801, 8.749939429];
KB = [1.69838, 2.41533, 3.48171, 4.66708];
% %LCB = [29.94300827, 29.8
plot(dispW,draft_y, KB,draft_y)
% Compute tick values for each axis to align with main axis
additionalAxisTicks = arrayfun(@(i){linspace(additionalAxisLimits(i,1), ...
additionalAxisLimits(i,2),numel(ax.XTick))}, 1:size(additionalAxisLimits,1));
% Set up multi-line ticks
allTicks = [ax.XTick; cell2mat(additionalAxisTicks')];
tickLabels = compose(repmat('%.2f\\newline',1,size(allTicks,1)), allTicks(:).');
% The %4d adds space to the left so the labels are centered.
% Decrease axis height & width to make room for labels
% Decrease axis height & width to make room for labels
ax.Position(3) = ax.Position(3) * .75; % Reduced width to 75%
ax.Position(4) = ax.Position(4) * .40; % Reduced height to 40%
ax.Position(2) = ax.Position(2) + .48; % move up
% Add x tick labels
set(ax, 'XTickLabel', tickLabels, 'TickDir', 'out')
% Define each row of labels
ax2 = axes('Position',[sum(ax.Position([1,3]))*1.1, ax.Position(2), 0.2, 0]);
linkprop([ax,ax2],{'TickDir','TickLength','FontSize'})
axisLabels = {'Area (m^2)', 'Distance (t)','Area (m^2)','Cnt from 0 (m)','KB (m)'}; % one for each x-axis
set(ax2,'XTick',0.5,'XLim',[0,1],'XTickLabel', strjoin(axisLabels,'\\newline'))
I only tried 2 out of 14
marked one is not correct!!!, Blue line is ok. how can I plot 14 different scale line??
You're asking me to do your entire project for you. I can help you learn but I will not do your work for you.
You need to normalize all of your x values so they match the scale of your main x axis.
Here's an example. You need to understand the example and apply it to your data.
First, you need to decide the lower and upper bounds of your x-axis range.
ax.XLim = [4000,30000];
Then you need to normalize the x-values to that range. The x values in my demo range from 20 to 30.
x = [22 30 26 25 24 25 25 22];
xBounds = [20,30];
% Normalize to the x-axis limits
xNorm = (x - xBounds(1))/range(xBounds) * range(ax.XLim) + ax.XLim(1);
Now plot your data using xNorm
plot(xNorm, y)
Repeat this for all lines. The y axis values will automatically adjust with the range of your data.
I am learning. What is normalize the X-values? Can you tell me this line, what this lines mean :
xNorm = (x - xBounds(1))/range(xBounds) * range(ax.XLim) + ax.XLim(1);
xNorm = (x - xBounds(1))/range(xBounds) * range(ax.XLim) + ax.XLim(1); in this line, what does "(1)" mean?
And where I have to write this codes, I mean which lines? at the end?
Sir, Please help me. I am not requesting you to do my project. I simply want to learn. I have stuck with this for last 3 days
"in this line, what does "(1)" mean?"
Look at the value of ax.XLim. The (1) selects the first element which is the lower x-limit.
Normalization is when you convert a set of data to a different scale. A well known example is percentages. 0.2, 0.5, 0.8 can be converted to 20%, 50%, 80% by multiplying by 100. Your normalization is a bit more complicated because the data must be scaled to fit within 4000-30000.
"And where I have to write this codes, I mean which lines? at the end?"
You can normalize the data anywhere in your code after the ax.XLim is set.
I suggest doing the plotting after the axes are all set up.
My answer does not add a second x-axis. Instead, it adds rows of x-tick-labels to represent additional axes at different scales. You could implement this idea but it would not show a second axis line and the tick intervals would differ. Matlab does not currently offer a method of adding addtional axis rulers (lines) but you could ask a new question or search the forum to find work-arounds.
Thank Adam for claryfication on this issues. However do you have any idea so that I can add second axis like that in Matlab? I would really grateful if you can share the idea. Thank you in advance.
Note, this method does not work with uiaxes.
Unfortunately the newlines don't get rendered, and you end up with just a single line for each tick label.
This is almost the same code as Adams, with uiaxes, and also forcing the label rotation to 0.
% Set up main axis (on top)
clf()
uif = uifigure('HandleVisibility','on');
ax = uiaxes(uif,'Position', [20 100 500 300]);
ax.XTick = 0:200:2800;
ax.XLim = [0,2800];
% Set axis limits for all other axes
additionalAxisLimits = [...
0, 1400; % axis 2
19.2, 23.4; % axis 3
0.2, 3]; % axis 4
% Compute tick values for each axis to align with main axis
additionalAxisTicks = arrayfun(@(i){linspace(additionalAxisLimits(i,1), ...
additionalAxisLimits(i,2),numel(ax.XTick))}, 1:size(additionalAxisLimits,1));
% Set up multi-line ticks
allTicks = [ax.XTick; cell2mat(additionalAxisTicks')];
tickLabels = compose('%4d\\newline%4d\\newline%.1f\\newline%.1f', allTicks(:).');
% The %4d adds space to the left so the labels are centered.
% You'll need to add "%.1f\\newline" for each row of labels (change formatting as needed).
% Alternatively, you can use the flexible line below that works with any number
% of rows but uses the same formatting for all rows.
% tickLabels = compose(repmat('%.2f\\newline',1,size(allTicks,1)), allTicks(:).');
% Decrease axis height & width to make room for labels
ax.Position(3:4) = ax.Position(3:4) * .75; % Reduced to 75%
ax.Position(2) = ax.Position(2) + .2; % move up
% Add x tick labels
set(ax, 'XTickLabel', tickLabels, 'TickDir', 'out','XTickLabelRotation',0)
% Define each row of labels
ax2 = uiaxes(uif,'Position',[sum(ax.Position([1,3]))*1.08, ax.Position(2), .02, 0.001]);
axisLabels = {'Distance (t)','Area (m^2)','Cnt from 0 (m)','KB (m)'}; % one for each x-axis
set(ax2,'XTick',0.5,'XLim',[0,1],'XTickLabel', strjoin(axisLabels,'\\newline'))
ax2.TickLength(1) = 0.2; % adjust as needed to align ticks between the two axes
linkprop([ax,ax2],{'TickDir','FontSize','XTickLabelRotation'});
@Matthew Mishrikey thanks for your comment. I recall having this problem in the past but now when I test it with your code in MATLAB R2022a, I don't see the problem. The only change I made was to increase the axes size so I can more clearly see the ticks. I wonder what release of MATLAB you're using.
The tick label rotation became a feature after I added my answer but thanks for the reminder to update my answer to set rotation to 0.
R2021a. Must've been fixed recently.

Sign in to comment.

More Answers (0)

Community Treasure Hunt

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

Start Hunting!