How to add labels on each line and add 2nd y-axes

2019-08-10 22:32发布

问题:

Recently I am trying to implement the ISO classification for the roadway assessment. Please refer to the paper The use of vehicle acceleration measurements to estimate road roughness. But I bumped into some questions about plotting the ISO classification graph. The code is shown as follows:

%% generate ISO Clasification Curve (m^2/(rad/m))
AngSpaFre = 10^(-3):0.01:10^2;                                  % spatial frequency (rad/m)
ParamTable = [0              1*10^(-6)       2*(10^(-6));       % ISO classification parameters
              2*(10^(-6))    4*(10^(-6))     8*(10^(-6));       % (lower bound, geometric average, upper bound)
              8*(10^(-6))    16*(10^(-6))    32*(10^(-6));
              32*(10^(-6))   64*(10^(-6))    128*(10^(-6));
              128*(10^(-6))  256*(10^(-6))   512*(10^(-6));
              512*(10^(-6))  1024*(10^(-6))  2048*(10^(-6));
              2048*(10^(-6)) 4096*(10^(-6))  8192*(10^(-6));
              8192*(10^(-6)) 16384*(10^(-6)) 32768*(10^(-6))];
class_num = 8;
len = length(AngSpaFre);
iso_table = zeros(class_num, len);
for i = 1:class_num
  geo_mean = ParamTable(i, 2);
  geo_upbound = ParamTable(i, 3);
  for j = 1:len
    if(AngSpaFre(j) <= 1)
        iso_table(i,j) = geo_mean*(AngSpaFre(j)^(-2));
    else
        iso_table(i,j) = geo_mean*(AngSpaFre(j)^(-1.5));
    end
  end
end

figure,
ht = loglog(AngSpaFre, iso_table(1,:), AngSpaFre, iso_table(2,:), AngSpaFre, iso_table(3,:), AngSpaFre, iso_table(4,:), AngSpaFre, iso_table(5,:), AngSpaFre, iso_table(6,:), AngSpaFre, iso_table(7,:), AngSpaFre, iso_table(8,:));
hY = get(gca,'ylim');
hold on;
loglog([1 1], hY);
xlabel('Spatial Frequency \Omega (rad/m)');
ylabel('PSD (m^2/(rad/m))'); 
title('ISO Classification (log-log scale)');

And the current result is illustrated as the figure bellow:

Then 2 questions comes in my implementation and hope any one could give me some solutions or simple examples to make the problems clear.

Q1: Since the classification curve should recognize the quality-level of a road. So I'd like to add labels below each line to indicate the level like the graph below. How can I realize this in matlab?

Q2: Also, I'd like to add another y-axis on the right-side of the 'loglog' plot without log-scale values like the figure below. How to achieve this? I've refer to many examples in official website but most focus on the 'plot'/'plotyy' examples. :(

回答1:

Answer Part I

The common way to put text somewhere is the annotation function. It's quite hard do get it right with its basic functions, so rather use it with the latex interpreter as it allows you to specify the gap between every line with '\vspace{gapwidth}' and a lot more options:

strings = {'H','G','F','E','D','C','B','A'};
verticalspace = '\vspace{4pt}';
str = cellfun(@(x) [x verticalspace],strings,'uni',0);


annotation('textbox', [0.4,0.6,0.1,0.1],...
           'String', str,...
           'LineStyle','none','Interpreter','latex');

It's definitely fiddly and you should use a fixed figure width.

An alternative is to use custom datatips and tweak them as desired. Advantage is that the position of the textbox is relative to your data and not figure.

My general recommendation: don't use Matlab at all for doing such tweaking, it's pain in the a... . Save your figure as pdf (set(gcf,'renderer','painters')) and do the post processing with any vector graphics program or directly with LaTeX/Tikz.

Answer Part II

To get a second axes, use:

ax1 = gca;
ax2 = axes('Position',ax1.Position,'Color','none');
ax2.YAxisLocation = 'right';
ax2.YLim = [0, 120];
ax2.YTick = 0:10:120;
ax2.XTick = [];

And again, specify the exact figure dimensions before! Resizing afterwards just makes troubles.

Summary

All together underneath your current code:

%%
f = gcf;
f.Units = 'pixels';
f.Position = ([100,100,1000,800]);

%%
strings = {'H','G','F','E','D','C','B','A'};
verticalspace = '\vspace{7.6pt}';
str = cellfun(@(x) [x verticalspace],strings,'uni',0);

annotation('textbox', [0.4,0.61,0.1,0.1],...
           'String', str,...
           'LineStyle','none','Interpreter','latex');

%%
ax1 = gca;
ax2 = axes('Position',ax1.Position,'Color','none');
ax2.YAxisLocation = 'right';
ax2.YLim = [0, 120];
ax2.YTick = 0:10:120;
ax2.XTick = [];
linkaxes([ax1,ax2],'x')

would give (not resized):