function transformation_linear_regression
%built by keith regner 10/2016 with R2014b (8.4 OSX)
clear all
close all

%% description
% This demo shows how transformations can be used to manipulate nonlinear 
% equations into a form for linear regression analysis. Four different 
% equations are shown on the right hand side of the window and can be 
% selected with the radio buttons. The selected nonlinear equation is 
% plotted in the upper left plot (dashed black line). Experimental data 
% are generated from this equation by adding white Gaussian noise and are 
% shown on the same plot (blue circles). These nonlinear experimental data 
% are fit with a linear model (solid green line). The residuals of that 
% fitting are shown in the lower left plot and exhibit a clear trend, 
% indicating the linear approximation is violated.
% 
% The nonlinear equation and experimental data are transformed accordingly 
% and shown in the upper right plot. The transformed data are fit with a 
% linear model. The residuals for the resulting fit are shown in the lower 
% right plot.

%% create x data
b.x_data = 0.05:.05:3;
b.snr = 1;

%% functions on radio buttons
%exponential y = 5*exp(x) + 2
b.y_data1 = 5*exp(b.x_data) + 2;
b.x_data1 = exp(b.x_data);
b.y_data_trans1 = 5*b.x_data1 + 2;
%quadratic y = 5*x^2 + 2
b.y_data2 = 5*(b.x_data.^-1) + 2; 
b.x_data2 = b.x_data.^-1;
b.y_data_trans2 = 5*b.x_data2 + 2;
%logarithmic y = 5*ln(x) + 2
b.y_data3 = 5*log(b.x_data) + 2;
b.x_data3 = log(b.x_data);
b.y_data_trans3 = 5*b.x_data3 + 2;
%logarithmic y = sqrt(5*x^3 + 2)
b.y_data4 = sqrt(5*(b.x_data.^5) + 2);
b.x_data4 = b.x_data.^5;
b.y_data_trans4 = 5*b.x_data4 + 2;

b.y_data = b.y_data1;
b.y_data_trans = b.y_data_trans1;
b.x_data_trans = b.x_data1;

b.y_data_ref = b.y_data;
b.y_data = awgn(b.y_data,b.snr);
b.y_data_trans_ref = b.y_data_trans;
b.y_data_trans = awgn(b.y_data_trans,b.snr);
b.data = [b.x_data' b.y_data'];
b.data_trans = [b.x_data_trans' b.y_data_trans'];

%% fit data
[a] = simp_lin_reg(b.data,b.x_data);
[a_trans] = simp_lin_reg(b.data_trans,b.x_data1);

%% figure and axis formatting
b.fig = figure('Units','inches','Position',[1.5 .5 14 8],...
    'Name','transformation_linear_regression','NumberTitle','off');
b.axover = axes('Units','inches','Position',[0 0 11 9],'Visible','off');
b.ax1 = axes('Units','inches','Position',[1 4.5 4 3],'FontSize',12,...
    'LineWidth',1.5,'XLim', [b.x_data(1) b.x_data(length(b.x_data))],...
    'YLim',[-20 120],'Box','on');
hold on
xlabel('$x$','Interpreter','latex','FontSize',14);
ylabel('$y$','Interpreter','latex','FontSize',14);

b.ax2 = axes('Units','inches','Position',[1 .8 4 3],'FontSize',12,...
    'LineWidth',1.5,'Box','on');
axis tight
b.ax2.YLim = [-20 30];
hold on
xlabel('$\hat{y}_{i}$','Interpreter','latex','FontSize',14);
ylabel('$y_{i}$ - $\hat{y}_{i}$','Interpreter','latex','FontSize',14);

b.ax3 = axes('Units','inches','Position',[6 4.5 4 3],'FontSize',12,...
    'LineWidth',1.5,'Box','on');
axis tight
hold on
xlabel('$\chi$','Interpreter','latex','FontSize',14);
ylabel('$\Psi$','Interpreter','latex','FontSize',14);

b.ax4 = axes('Units','inches','Position',[6 .8 4 3],'FontSize',12,...
    'LineWidth',1.5,'Box','on');
axis tight
b.ax4.YLim = [-3.5 3.5];
hold on
xlabel('$\hat{\Psi}_{i}$','Interpreter','latex','FontSize',14);
ylabel('$\Psi_{i}$ - $\hat{\Psi}_{i}$','Interpreter','latex','FontSize',14);

%% plot solution
%data and fit
b.h_data = plot(b.ax1,b.data(:,1),b.data(:,2),'o','MarkerFaceColor',...
    [0 0.44 0.74],'MarkerEdgeColor','k','MarkerSize',6);
b.h_fit = plot(b.ax1,b.x_data,a.y_hat,'Color',[0 1 0],...
    'LineWidth',1.5);
b.h_ref = plot(b.ax1,b.x_data,b.y_data_ref,'Color',[0 0 0],...
    'LineWidth',.5,'LineStyle','--');
b.point_leg = plot(b.ax1,4,4,'o','MarkerFaceColor',...
    [1 1 1],'MarkerEdgeColor','k','MarkerSize',6,'Visible','off');
b.leg = legend(b.ax1,[b.point_leg],{'data'},...
    'Location','NorthWest','Box','off','FontSize',12);

%residuals
b.h_res_data = plot(b.ax2,b.data(:,2),a.res,'o',...
    'MarkerFaceColor',[0 0.44 0.74],'MarkerEdgeColor','k','MarkerSize',6);
b.h_res_ref = plot(b.ax2,b.data(:,2),b.data(:,2)*0,'Color',[0 0 0],...
    'LineWidth',1.5);

%data_trans and fit
b.h_data_trans = plot(b.ax3,b.data_trans(:,1),b.data_trans(:,2),...
    'o','MarkerFaceColor',[0 0.44 0.74],'MarkerEdgeColor',...
    'k','MarkerSize',6);
b.h_fit_trans = plot(b.ax3,b.x_data_trans,a_trans.y_hat,'Color',[0 1 0],...
    'LineWidth',1.5);
b.h_ref_trans = plot(b.ax3,b.x_data1,b.y_data_trans_ref,'Color',[0 0 0],...
    'LineWidth',.5,'LineStyle','--');
b.point_leg_trans = plot(b.ax3,4,4,'o','MarkerFaceColor',...
    [1 1 1],'MarkerEdgeColor','k','MarkerSize',6,'Visible','off');
b.leg_trans = legend(b.ax3,[b.point_leg_trans],{'data'},...
    'Location','NorthWest','Box','off','FontSize',12);

%residuals_trans
b.h_res_data_trans = plot(b.ax4,b.data_trans(:,2),a_trans.res,...
    'o','MarkerFaceColor',[0 0.44 0.74],'MarkerEdgeColor',...
    'k','MarkerSize',6);
b.h_res_ref_trans = plot(b.ax4,b.data_trans(:,2),b.data_trans(:,2)*0,...
    'Color',[0 0 0],'LineWidth',1.5);

%% more legend
%data
b.line_fit = annotation('line','Units','inches','x',[1.2 1.63],...
    'y',[6.72 6.72],'LineWidth',1.5,'Color',[0 1 0]);
b.txtboxf1 = annotation('textbox','Units','inches','Position',...
    [1.61 6.5 4 .3],'String','fit, ','FontSize',12,'LineStyle',...
    'none');
b.txtbox1 = annotation('textbox','Units','inches','Position',...
    [1.83 6.55 4 .3],'String',...
    ['$\hat{y}$ = ' num2str(round(a.B_hat1,2)) '\textit{x} + ' ...
    num2str(round(a.B_hat0,2)) ','],'FontSize',14,'LineStyle','none',...
    'Interpreter','latex');
b.txtbox2 = annotation('textbox','Units','inches','Position',...
    [1.83 6.25 4 .3],'String',...
    ['$r^{2}$ = ' num2str(a.r^2)],'FontSize',14,'LineStyle',...
    'none','Interpreter','latex');

b.line_act = annotation('line','Units','inches','x',[1.2 1.63],...
    'y',[7.02 7.02],'LineWidth',.5,'Color',[0 0 0],'LineStyle','--');
b.txtboxactl = annotation('textbox','Units','inches','Position',...
    [1.61 6.8 4 .3],'String','actual, ','FontSize',12,'LineStyle',...
    'none');
b.txtboxact = annotation('textbox','Units','inches','Position',...
    [2.15 6.85 4 .3],'String',...
    '${y}$ = 5${e}^{x}$ + 2','FontSize',...
    14,'LineStyle','none','Interpreter','latex');

%data trans
b.line_fit_trans = annotation('line','Units','inches','x',[6.2 6.63],...
    'y',[6.72 6.72],'LineWidth',1.5,'Color',[0 1 0]);
b.txtboxf2 = annotation('textbox','Units','inches','Position',...
    [6.61 6.5 4 .3],'String','fit, ','FontSize',12,'LineStyle',...
    'none');
b.txtbox1t = annotation('textbox','Units','inches','Position',...
    [6.83 6.55 4 .3],'String',...
    ['$\hat{\Psi}$ = ' num2str(round(a_trans.B_hat1,2)) '${\chi}$ + ' ...
    num2str(round(a_trans.B_hat0,2)) ','],'FontSize',14,'LineStyle',...
    'none','Interpreter','latex');
b.txtbox2t = annotation('textbox','Units','inches','Position',...
    [6.83 6.25 4 .3],'String',...
    ['$r^{2}$ = ' num2str(a_trans.r^2)],'FontSize',14,'LineStyle',...
    'none','Interpreter','latex');

b.line_act_trans = annotation('line','Units','inches','x',[6.2 6.63],...
    'y',[7.02 7.02],'LineWidth',.5,'Color',[0 0 0],'LineStyle','--');
b.txtboxactl_trans = annotation('textbox','Units','inches','Position',...
    [6.61 6.8 4 .3],'String','actual, ','FontSize',12,'LineStyle',...
    'none');
b.txtboxact_trans = annotation('textbox','Units','inches','String',...
    '${\Psi}$ = 5${\chi}$ + 2',...
    'Position',[7.15 6.85 4 .3],'FontSize',14,'LineStyle','none',...
    'Interpreter','latex');

%% add user control
bg = uibuttongroup('Visible','off','Units','inches','Position',...
    [10.2 5.5 .6 2.3],'SelectionChangedFcn',...
    {@bselection,b},'BorderType',...
    'none');
r1 = uicontrol('Parent',bg,'Style','radiobutton','String','1.',...
    'FontSize',12,'Units','inches','Position',[.05 1.75 .7 .3],...
    'HandleVisibility','off');
r2 = uicontrol('Parent',bg,'Style','radiobutton','String','2.',...
    'FontSize',12,'Units','inches','Position',[.05 1.25 .7 .3],...
    'HandleVisibility','off');
r3 = uicontrol('Parent',bg,'Style','radiobutton','String','3.',...
    'FontSize',12,'Units','inches','Position',[.05 .75 .7 .3],...
    'HandleVisibility','off');
r4 = uicontrol('Parent',bg,'Style','radiobutton','String','4.',...
    'FontSize',12,'Units','inches','Position',[.05 .25 .7 .3],...
    'HandleVisibility','off');
bg.Visible = 'on';

b.txtboxr1 = annotation('textbox','Units','inches','Position',...
    [10.8 7.25 3.5 .3],'String',...
    '${y}$ = 5${e}^{x}$ + 2, ${\Psi}$ = ${y}$, ${\chi}$ = ${e}^{x}$',...
    'FontSize',14,'Interpreter','latex','LineStyle','none');
b.txtboxr2 = annotation('textbox','Units','inches','Position',...
    [10.8 6.75 3.5 .3],'String',...
    '${y}$ = 5${x}^{-1}$ + 2, ${\Psi}$ = ${y}$, ${\chi}$ = ${x}^{-1}$',...
    'FontSize',14,'Interpreter','latex','LineStyle','none');
b.txtboxr3 = annotation('textbox','Units','inches','Position',...
    [10.8 6.25 3.5 .3],'String',...
    '${y}$ = 5ln(${x}$) + 2, ${\Psi}$ = ${y}$, ${\chi}$ = ln(${x}$)',...
    'FontSize',14,'Interpreter','latex','LineStyle','none');
b.txtboxr4 = annotation('textbox','Units','inches','Position',...
    [10.8 5.75 3.5 .3],'String',...
    '${y}^{2}$ = $5{x}^{5} + 2$, ${\Psi}$ = ${y}^{2}$, ${\chi}$ = ${x}^{5}$',...
    'FontSize',14,'Interpreter','latex','LineStyle','none');

set(findall(b.fig,'-property','FontUnits'),'FontUnits','normalized')
set(findall(b.fig,'-property','Units'),'Units','normalized')

end

%% callback functions
function bselection(varargin)
[H,b] = varargin{[1,3]};
if H.SelectedObject.String == '1.'
    y_data = b.y_data1;
    y_data_trans = b.y_data_trans1;
    x_data_trans = b.x_data1;
    
    y_data_ref = y_data;
    y_data = awgn(y_data,b.snr);
    y_data_trans_ref = y_data_trans;
    y_data_trans = awgn(y_data_trans,b.snr);
    data = [b.x_data' y_data'];
    data_trans = [x_data_trans' y_data_trans'];
    [a] = simp_lin_reg(data,b.x_data);
    [a_trans] = simp_lin_reg(data_trans,b.x_data1);
    
    set(b.h_data,'XData',data(:,1),'YData',data(:,2));
    set(b.h_fit,'YData',a.y_hat);
    set(b.h_ref,'YData',y_data_ref);
    set(b.h_res_data,'XData',data(:,2),'YData',a.res);
    set(b.h_res_ref,'XData',data(:,2),'YData',data(:,2)*0);
    set(b.h_data_trans,'XData',data_trans(:,1),'YData',data_trans(:,2));
    set(b.h_fit_trans,'XData',x_data_trans,'YData',a_trans.y_hat);
    set(b.h_ref_trans,'XData',x_data_trans,'YData',y_data_trans_ref);
    set(b.h_res_data_trans,'XData',data_trans(:,2),'YData',a_trans.res);
    set(b.h_res_ref_trans,'XData',data_trans(:,2),'YData',data_trans(:,2)*0);
    set(b.txtbox1,'String',...
        ['$\hat{y}$ = ' num2str(round(a.B_hat1,2)) '${x}$ + ' ...
        num2str(round(a.B_hat0,2)) ',']);
    set(b.txtbox2,'String',['$r^{2}$ = ' num2str(a.r^2)]);
    set(b.txtbox1t,'String',...
        ['$\hat{\Psi}$ = ' num2str(round(a_trans.B_hat1,2)) '${\chi}$ + ' ...
        num2str(round(a_trans.B_hat0,2)) ',']);
    set(b.txtbox2t,'String',['$r^{2}$ = ' num2str(a_trans.r^2)]);
    b.ax1.YLim = [-20 120];
    b.ax2.YLim = [-20 30];

    set(b.txtboxact_trans,'String','${\Psi}$ = 5${\chi}$ + 2')
    set(b.txtboxact,'String','${y}$ = 5${e}^{x}$ + 2');   
end
if H.SelectedObject.String == '2.'
    y_data = b.y_data2;
    y_data_trans = b.y_data_trans2;
    x_data_trans = b.x_data2;

    y_data_ref = y_data;
    y_data = awgn(y_data,b.snr);
    y_data_trans_ref = y_data_trans;
    y_data_trans = awgn(y_data_trans,b.snr);
    data = [b.x_data' y_data'];
    data_trans = [x_data_trans' y_data_trans'];
    [a] = simp_lin_reg(data,b.x_data);
    [a_trans] = simp_lin_reg(data_trans,b.x_data2);
    
    set(b.h_data,'XData',data(:,1),'YData',data(:,2));
    set(b.h_fit,'YData',a.y_hat);
    set(b.h_ref,'YData',y_data_ref);
    set(b.h_res_data,'XData',data(:,2),'YData',a.res);
    set(b.h_res_ref,'XData',data(:,2),'YData',data(:,2)*0);
    set(b.h_data_trans,'XData',data_trans(:,1),'YData',data_trans(:,2));
    set(b.h_fit_trans,'XData',x_data_trans,'YData',a_trans.y_hat);
    set(b.h_ref_trans,'XData',x_data_trans,'YData',y_data_trans_ref);
    set(b.h_res_data_trans,'XData',data_trans(:,2),'YData',a_trans.res);
    set(b.h_res_ref_trans,'XData',data_trans(:,2),'YData',data_trans(:,2)*0);
    set(b.txtbox1,'String',...
        ['$\hat{y}$ = ' num2str(round(a.B_hat1,2)) '${x}$ + ' ...
        num2str(round(a.B_hat0,2)) ',']);
    set(b.txtbox2,'String',['$r^{2}$ = ' num2str(a.r^2)]);
    set(b.txtbox1t,'String',...
        ['$\hat{\Psi}$ = ' num2str(round(a_trans.B_hat1,2)) '${\chi}$ + ' ...
        num2str(round(a_trans.B_hat0,2)) ',']);
    set(b.txtbox2t,'String',['$r^{2}$ = ' num2str(a_trans.r^2)]);
    
    b.ax1.YLim = [-20 110];
    b.ax2.YLim = [-15 80];

    set(b.txtboxact_trans,'String','${\Psi}$ = 5${\chi}$ + 2')
    set(b.txtboxact,'String','${y}$ = 5${x}^{-1}$ + 2');
end
if H.SelectedObject.String == '3.'
    
    y_data = b.y_data3;
    y_data_trans = b.y_data_trans3;
    x_data_trans = b.x_data3;

    y_data_ref = y_data;
    y_data = awgn(y_data,b.snr);
    y_data_trans_ref = y_data_trans;
    y_data_trans = awgn(y_data_trans,b.snr);
    data = [b.x_data' y_data'];
    data_trans = [x_data_trans' y_data_trans'];
    [a] = simp_lin_reg(data,b.x_data);
    [a_trans] = simp_lin_reg(data_trans,b.x_data3);
    set(b.h_data,'XData',data(:,1),'YData',data(:,2));
    set(b.h_fit,'YData',a.y_hat);
    set(b.h_ref,'YData',y_data_ref);
    set(b.h_res_data,'XData',data(:,2),'YData',a.res);
    set(b.h_res_ref,'XData',data(:,2),'YData',data(:,2)*0);
    set(b.h_data_trans,'XData',data_trans(:,1),'YData',data_trans(:,2));
    set(b.h_fit_trans,'XData',x_data_trans,'YData',a_trans.y_hat);
    set(b.h_ref_trans,'XData',x_data_trans,'YData',y_data_trans_ref);
    set(b.h_res_data_trans,'XData',data_trans(:,2),'YData',a_trans.res);
    set(b.h_res_ref_trans,'XData',data_trans(:,2),'YData',data_trans(:,2)*0);
    set(b.txtbox1,'String',...
        ['$\hat{y}$ = ' num2str(round(a.B_hat1,2)) '${x}$ + ' ...
        num2str(round(a.B_hat0,2)) ',']);
    set(b.txtbox2,'String',['$r^{2}$ = ' num2str(a.r^2)]);
    set(b.txtbox1t,'String',...
        ['$\hat{\Psi}$ = ' num2str(round(a_trans.B_hat1,2)) '${\chi}$ + ' ...
        num2str(round(a_trans.B_hat0,2)) ',']);
    set(b.txtbox2t,'String',['$r^{2}$ = ' num2str(a_trans.r^2)]);
    b.ax1.YLim = [-20 30];
    b.ax2.YLim = [-10 5];

    set(b.txtboxact_trans,'String','${\Psi}$ = 5${\chi}$ + 2')
    set(b.txtboxact,'String','${y}$ = 5ln(${x}$) + 2');
end
if H.SelectedObject.String == '4.'
    
    y_data = b.y_data4;
    y_data_trans = b.y_data_trans4;
    x_data_trans = b.x_data4;

    y_data_ref = y_data;
    y_data = awgn(y_data,b.snr);
    y_data_trans_ref = y_data_trans;
    y_data_trans = awgn(y_data_trans,b.snr);
    data = [b.x_data' y_data'];
    data_trans = [x_data_trans' y_data_trans'];
    [a] = simp_lin_reg(data,b.x_data);
    [a_trans] = simp_lin_reg(data_trans,b.x_data4);
    set(b.h_data,'XData',data(:,1),'YData',data(:,2));
    set(b.h_fit,'YData',a.y_hat);
    set(b.h_ref,'YData',y_data_ref);
    set(b.h_res_data,'XData',data(:,2),'YData',a.res);
    set(b.h_res_ref,'XData',data(:,2),'YData',data(:,2)*0);
    set(b.h_data_trans,'XData',data_trans(:,1),'YData',data_trans(:,2));
    set(b.h_fit_trans,'XData',x_data_trans,'YData',a_trans.y_hat);
    set(b.h_ref_trans,'XData',x_data_trans,'YData',y_data_trans_ref);
    set(b.h_res_data_trans,'XData',data_trans(:,2),'YData',a_trans.res);
    set(b.h_res_ref_trans,'XData',data_trans(:,2),'YData',data_trans(:,2)*0);
    set(b.txtbox1,'String',...
        ['$\hat{y}$ = ' num2str(round(a.B_hat1,2)) '${x}$ + ' ...
        num2str(round(a.B_hat0,2)) ',']);
    set(b.txtbox2,'String',['$r^{2}$ = ' num2str(a.r^2)]);
    set(b.txtbox1t,'String',...
        ['$\hat{\Psi}$ = ' num2str(round(a_trans.B_hat1,2)) '${\chi}$ + ' ...
        num2str(round(a_trans.B_hat0,2)) ',']);
    set(b.txtbox2t,'String',['$r^{2}$ = ' num2str(a_trans.r^2)]);
    b.ax1.YLim = [-20 30];
    b.ax2.YLim = [-10 10];

    set(b.txtboxact_trans,'String','${\Psi}$ = 5${\chi}$ + 2')
    set(b.txtboxact,'String','${y}$ = $\sqrt{5{x}^{5} + 2}$');
end
end

%% simple linear regression function
function [a] = simp_lin_reg(data,x)
a.x_bar = mean(data(:,1));
a.y_bar = mean(data(:,2));
a.B_hat1 = sum((data(:,1)-a.x_bar).*(data(:,2)-a.y_bar))/...
    sum((data(:,1)-a.x_bar).^2);
a.B_hat0 = a.y_bar - a.B_hat1*a.x_bar;
a.y_hat = a.B_hat0 + a.B_hat1*x;
a.r = sum((data(:,1)-a.x_bar).*(data(:,2)-a.y_bar))/...
    (sqrt(sum(((data(:,1)-a.x_bar).^2)))*...
    sqrt(sum(((data(:,2)-a.y_bar).^2))));
y_hat_res = a.B_hat0 + a.B_hat1*data(:,1);
a.res = data(:,2) - y_hat_res;
end

