This question may seem like it has been answered in the forums but I believe there is a subtlety that has not been directly answered. I want to plot the optical absorption coefficient of a material as a function of both photon wavelength (bottom x-axis) and energy (top x-axis) similar to this figure shown below. There are two problems with this task that I have not found sufficiently addressed. The first is to ensure that all of the points in the bottom axis line up with the points in the top axis (we need to some how link the two x-axes). Second, because of how energy and wavelength are related, one axis will be ascending while the other will be descending (Matlab doesn't like descending x-axes). How can you make the referenced plot? Can someone recreate the reference plot using the following data taken from the reference plot?
clear
close all
data = [0.35737704918032787, 92649850.48039015
0.3819672131147541, 72475211.53588514
0.41147540983606556, 55967196.301264346
0.4229508196721312, 51126728.207795605
0.4557377049180328, 47937263.23846833
0.5016393442622952, 43803474.996365294
0.539344262295082, 40544606.59504045
0.5688524590163934, 34277014.89316264
0.5950819672131147, 25461360.619704828
0.6229508196721312, 16618285.037019765
0.6655737704918033, 10037712.197086804
0.7213114754098361, 6724703.556947659
0.7950819672131147, 4169337.0144349397
0.8836065573770491, 2722604.5977291227
0.9557377049180328, 1997130.2156342946
1.0344262295081967, 1523018.3932672704
1.1049180327868853, 1255113.4937515096
1.1852459016393442, 1034416.372625131
1.2737704918032788, 886319.8712540427
1.359016393442623, 779309.6059234422
1.4540983606557378, 609961.3425615291
1.4918032786885247, 502533.5248888627
1.5098360655737708, 398203.214420678
1.5196721311475412, 299601.3683763488
1.5213114754098362, 195504.2893801002
1.5262295081967214, 119588.7737216253
1.5360655737704918, 65114.84416472715
1.5475409836065577, 38316.26954492593
1.5508196721311474, 25329.082065449114
1.559016393442623, 18331.533361062826
1.5688524590163935, 14713.897024069562
1.5934426229508198, 11361.99263934681
1.6196721311475408, 8773.786275376307
1.6508196721311474, 6433.761487810411
1.6754098360655738, 5032.800618487584
1.7049180327868854, 3787.196421050415
1.7327868852459019, 2886.942647505133
1.7557377049180327, 2287.679320744783
1.777049180327869, 1933.9100405245356];
%planks constant
h = 4.135e-15; %eV s
%speed of light
c = 3e8; %m/s
%Ge absorption coef
alpha = data(:,2); %1/m
%wavelength
lambda = data(:,1); %microns
%energy
E = h*c./(lambda*1e-6); %eV
figure(1)
plot(lambda,alpha,'r')
xlabel('Wavelength (\mum)')
ylabel('\alpha (m^{-1})')
set(gca,'Yscale','log')
figure(2)
plot(E,alpha,'r')
xlabel('Energy (eV)')
ylabel('\alpha (m^{-1})')
set(gca,'Yscale','log')

6 Comments

What do you mean by 'Matlab doesn't like descending x-axes'?
The following works fine for me to reverse an x-axis, though obviously it is a trivial case.
figure; hAxes = gca;
hAxes.XDir = 'reverse'
I'm also not sure what you mean by the points on top and bottom x-axis 'lining up' (I don't really see in the link you gave an obvious example of what you are asking). Do you mean you want the ticks on the two axes to line up even though they are showing two different properties?
Thank you for the answer for reversing the axis direction. I didn't know that you could do that.
Energy and wavelength are related and so any "tick" on the bottom x-axis (wavelength) must line up with its corresponding energy on the top x-axis. Otherwise the top axis has no meaning when related to the y-axis.
%planks constant
h = 4.135e-15; %eV s
%speed of light
c = 3e8; %m/s
%wavlength
lambda = linspace(200e-9,800e-9,100); %m
%energy
E = h*c./lambda; %eV
However, the science obsures the point. In the first post, I want to make sure the points on x1 and x2 axis line up. Specifically, I want x1(1) to line up--be directly below--x2(2) and so on.
Well, if you set the limits of both axes then they will line up. The exact ticks will likely not line up with ticks on the other axes, but if you want that too then you would need to edit the XTick and maybe XTickLabel properties as appropriate, as well as the XLim properties. Zooming in would be a problem though.
In which case your best bet would, perhaps be to have the exact same ticks for each axes and use only the XTickLabel property of the 2nd axis to give the true value. Then you can use
doc linkaxes
to ensure the ranges stay linked. I don't like using XTickLabels rather than actual XTick values like this myself because data cursor reporting and stuff like that is incorrect as it is based on the actual axis values, not any labels applied to the ticks.
Adam, I've editted the question a little and added some data taken from the reference plot. Do you think you could recreat the reference plot based on what I have provided?
Note that a similar solution was offered for the same question (and same OP) a while back,
That's my question but the code does not work. Since there was no activity on it in about 2 years I reposted it. Note, the answer was not accepted.

Sign in to comment.

 Accepted Answer

Ameer Hamza
Ameer Hamza on 9 Mar 2020
Edited: Ameer Hamza on 2 Oct 2020
data = [0.35737704918032787, 92649850.48039015
0.3819672131147541, 72475211.53588514
0.41147540983606556, 55967196.301264346
0.4229508196721312, 51126728.207795605
0.4557377049180328, 47937263.23846833
0.5016393442622952, 43803474.996365294
0.539344262295082, 40544606.59504045
0.5688524590163934, 34277014.89316264
0.5950819672131147, 25461360.619704828
0.6229508196721312, 16618285.037019765
0.6655737704918033, 10037712.197086804
0.7213114754098361, 6724703.556947659
0.7950819672131147, 4169337.0144349397
0.8836065573770491, 2722604.5977291227
0.9557377049180328, 1997130.2156342946
1.0344262295081967, 1523018.3932672704
1.1049180327868853, 1255113.4937515096
1.1852459016393442, 1034416.372625131
1.2737704918032788, 886319.8712540427
1.359016393442623, 779309.6059234422
1.4540983606557378, 609961.3425615291
1.4918032786885247, 502533.5248888627
1.5098360655737708, 398203.214420678
1.5196721311475412, 299601.3683763488
1.5213114754098362, 195504.2893801002
1.5262295081967214, 119588.7737216253
1.5360655737704918, 65114.84416472715
1.5475409836065577, 38316.26954492593
1.5508196721311474, 25329.082065449114
1.559016393442623, 18331.533361062826
1.5688524590163935, 14713.897024069562
1.5934426229508198, 11361.99263934681
1.6196721311475408, 8773.786275376307
1.6508196721311474, 6433.761487810411
1.6754098360655738, 5032.800618487584
1.7049180327868854, 3787.196421050415
1.7327868852459019, 2886.942647505133
1.7557377049180327, 2287.679320744783
1.777049180327869, 1933.9100405245356];
fig = figure();
% setup bottom axis
ax = axes();
hold(ax);
ax.YAxis.Scale = 'log';
xlabel(ax, 'Wavelength ($\mu$m)', 'Interpreter', 'latex', 'FontSize', 14);
ylabel(ax, '$\alpha$ ($m^{-1}$)', 'Interpreter', 'latex', 'FontSize', 14);
% setup top axis
ax_top = axes(); % axis to appear at top
hold(ax_top);
ax_top.XAxisLocation = 'top';
ax_top.YAxisLocation = "right";
ax_top.YTick = [];
% ax_top.XDir = 'reverse';
ax_top.Color = 'none';
xlabel(ax_top, 'Energy($e$V)', 'Interpreter', 'latex', 'FontSize', 14);
% linking axis
linkprop([ax, ax_top],{'Units','Position','ActivePositionProperty'});
ax.Position(4) = ax.Position(4) * .96;
h = 4.135e-15; %eV s
c = 3e8; %m/s
lambda = linspace(0.2,1.8,9); %m
E = h*c./lambda*10^6; % 10^6 because lambda is in microns
% configure limits of bottom axis
ax.XLim = [lambda(1) lambda(end)];
ax.XTick = lambda;
ax.XAxis.TickLength = [0.015, 0.00];
ax.YAxis.TickLength = [0.02, 0.00];
ax.XAxis.MinorTick = 'on';
ax.XAxis.MinorTickValues = linspace(0.2,1.8,17);
% configure limits and labels of top axis
y_ticks = [0.7 0.8 0.9 1 2 3 4 5];
lambda_y_tick = h*c./y_ticks*10^6;
ax_top.XLim = [lambda(1) lambda(end)];
ax_top.XTick = fliplr(lambda_y_tick);
ax_top.XTickLabel = compose('%1.1f', fliplr(y_ticks));
ax_top.XAxis.TickLength = [0.02, 0.00];
ax_top.XAxis.MinorTick = 'off';
plot(ax, data(:,1), data(:,2), 'r-', 'LineWidth', 3);

18 Comments

This does not solve the problem of lining up the top and bottom axes.
You need to specify it yourself. For example, if you are working with the wavelength and energy of a photon, then the relation is: , Then you can do something like this
h = % define value of h
c = % define value of c
% suppose wavelength axis is at top
ax_top.XLim = [400 700]; % limits of the wavelength axis
ax.XLim = fliplr(h*c./ax_top.XLim); % calculate limits of the energy axis
In this way, the limits of both axes are automatically bounded.
Can you try this the code I just posted above. I'm pretty sure it doesn't work.
There was an issue with the second limit. Check the updated code. It should run fine now. Note, values of h and c need to be added according to your units.
Ameer Hamza
Ameer Hamza on 9 Mar 2020
Edited: Ameer Hamza on 9 Mar 2020
Based on your comments, it appears that you also want to preserve the nonlinear relation between the two axes. Although MATLAB does not provide a direct way to do this however there is a bodge to make it look nonlinear. I have updated the code to just changes the axes label on the top axes to show the nonlinear relation. Note that this solution will break down if you try to zoom or move the axis manually.
Hi Ammer. Thanks for your efforts. I've changed the question code to include the data from the reference plot. Do you think you could recreate the reference plot from what I have provided?
What are the units of lambda? In one of the previous comment, you mentioned the range of lambda to be
lambda = linspace(200e-9,800e-9,100); %m
But the first column seems to contain values in range [0.3 1.8].
Also, which specific figure number you are referring in the link. The link opens all the figures in that book.
I've attached the figure above. The units are in comments, microns, micrometers.
Christopher Saltonstall, check the updated code. Although the code is a bit messy and uses tricks to display labels on the top axis, it creates the same graph.
This is great. Its only taken 2 years.
One minor question though. Why does the top x-axis seem to be shifted below the top border?
Answer: Its because the axes positions need to be aligned.
ax_top.Position = ax.Position;
+1, Ameer
I suggest using
linkprop([ax, ax_top],{'Units','Position','ActivePositionProperty'});
to make sure the axis positions are always aligned.
You may also want to decrease the height of the axes so the title, shifted by the upper ticks, doesn't go off the figure border. After the line above,
ax.Position(4) = ax.Position(4) * .92;
Adam, Thanks for the suggestion. I have updated the code in my answer to link and change the height of both axes.
Now the tick marks are off on the top axis.
Remove the line
box(ax);
How would you add a legend to this kind of plot? I've tried both the legend command and the DisplayName property but neither work in this case.
Specify the axes on which you want to place the legend.
plot(ax, data(:,1), data(:,2), 'r-', 'LineWidth', 3, 'DisplayName', 'Line 1');
legend(ax);
Hi Ameer Hamza,
May I know is it possible to use your code to plot like a picture below? Because I would like to plot 2 x-axis as per depicts in figure below.

Sign in to comment.

More Answers (0)

Categories

Tags

Community Treasure Hunt

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

Start Hunting!