0
votes

I have a script which fits some optical data to a sum of Lorentzian oscillators, and then spits out a figure with the original data and the fit. I would also like to include a text annotation with a table of the fitting parameters, but cannot figure out how to get rows and columns in my text box.

Each peak has 3 parameters and then there are 3 more global fitting parameters. My first try was to do this:

ParamTableLabels = {'\omega_p (cm^{-1})', '\omega_0 (cm^{-1})', '\Gamma (cm^{-1})'};
ParamTableVals = num2cell(Ef);
ParamTableLabels2 = {'d (\mu{m})','\epsilon_\infty','Scale'};
ParamTableVals2 = {ThickFit,EinfFit,ScaleFit};
ParamTable = vertcat(ParamTableLabels,ParamTableVals,ParamTableLabels2,ParamTableVals2);

where Ef is my 3xN matrix of fitting parameters. After generating my figure, I try to place the table in my plot at a suitable set of coordinates X,Y using:

text(X,Y,ParamTable)

and the result is a single column of text, no rows. My second attempt, which sort of works is to break up each column:

text(X,     Y,ParamTable(:,1));
text(X+dX,  Y,ParamTable(:,2));
text(X+2*dX,Y,ParamTable(:,3));

This almost works, but the subscripts in the labels throw off the vertical alignment of the last few rows, and it takes an undue amount of tinkering to get the spacing correct. I'm spending more time trying to get the text box to look right than to do the actual modelling.

How can I programatically format a block of text, containing both labels and variables, into rows and columns, and then use it as a text annotation in a figure with minimal user tinkering?

1
It's always nice when the included code is stand-alone executable. EG, this code is missing defintiions for Ef, ThickFit etc. Even if you make up random data.Pursuit

1 Answers

0
votes

This is a not well supported using basic commands. But you can at least save yourself the trouble of guessing the subsequent X positions by making Matlab do the work for you.

The key is the "Extent" read-only parameter attached to a text block. Use docsearch text properties to see the documentation.

Putting this into some code:

        padFraction = 0.1;  %This is roughly the unitless padding between columns, as a fraction of the column on the left.
        curX = X;           %Leave the initial X variable unchanged


        %For each text block column, add the text block, get the extent, and adjust curX
        h = text(curX,     Y,ParamTable(:,1));
        curExtent = get(h, 'Extent');
        curX = curExtent(1) + curExtent(3)*(1+padFraction);

        h = text(curX,  Y,ParamTable(:,2));
        curExtent = get(h, 'Extent');
        curX = curExtent(1) + curExtent(3)*(1+padFraction);

        text(curX,Y,ParamTable(:,3));

The full script used to generate/test is below:

ParamTableLabels = {'\omega_p (cm^{-1})', '\omega_0 (cm^{-1})', '\Gamma (cm^{-1})'};

Ef = round(rand(10,3)*100);
ParamTableVals = num2cell(Ef);
ParamTableLabels2 = {'d (\mu{m})','\epsilon_\infty','Scale'};
ParamTableVals2 = {'ThickFit','EinfFit','ScaleFit'};
ParamTable = vertcat(ParamTableLabels,ParamTableVals,ParamTableLabels2,ParamTableVals2);

X = 1;  Y = 1.1;


%Put something in the plot
figure(1); clf; hold on;
plot(-10:10, randn(21,1)*20,'.');

codeblock = 3;
switch codeblock
    case 1
        text(X,Y,ParamTable)

    case 2
        dX = 3;
        text(X,     Y,ParamTable(:,1));
        text(X+dX,  Y,ParamTable(:,2));
        text(X+2*dX,Y,ParamTable(:,3));

    case 3
        padFraction = 0.1;
        curX = X;

        h = text(curX,     Y,ParamTable(:,1));
        curExtent = get(h, 'Extent');
        curX = curExtent(1) + curExtent(3)*(1+padFraction);

        h = text(curX,  Y,ParamTable(:,2));
        curExtent = get(h, 'Extent');
        curX = curExtent(1) + curExtent(3)*(1+padFraction);

        text(curX,Y,ParamTable(:,3));
end