% File "Fit_Main" is used as a computing and plotting space for the
% problem at hand, and calls functions as needed.
% Note: For clarity's sake, the wild-type, mutant 1, and mutant 2 variables are kept
% separate throughout the code for Parts 1 and 2. However, they could readily be bundled
% into multidimensional matrices for cleaner code, as in Part 3.
clear all; % rid old parameter values, etc.
%% INPUT DATA BELOW
% Ligand concentrations (L) should all be in uM.
% Input normalized fluorescence signals (S) rather than raw data. To avoid divide
% by zero errors, put 0.9999 and 0.0001 in place of 1 and 0, respectively.
% "wt" refers to wild-type, and "m" to mutant.
L= [x x x x x x x x x x x x];
S_wt = [x x x x x x x x x x x x];
S_m1 = [x x x x x x x x x x x x];
S_m2 = [x x x x x x x x x x x x];
% Below we initialize an array of ligand concentrations values for use in
% our models. The values are in the appropriate range to compare fits to data.
L_space = logspace(-4, 4, 10000);
%% PART 1: Fit for single KD value using a simple model.
% This model ignores the fact of multiple binding sites, but will provide a
% useful introduction to our modeling methods.
C0 = 0; % initialize KD parameter as zero.
% Binding fractions are calculated from fluorescence below.
% Why can't the fluorescence data be used directly?
Y_wt = 1 - S_wt;
Y_m1 = 1 - S_m1;
Y_m2 = 1 - S_m2;
% Now we use the nonlinear fitting tool, nlinfit, to determine KD
% values, according to the model in function "Fit_SingleKD."
% The parameter C_x returns KD, and r returns residuals. Residuals show
% the difference between the model and data for any given data point.
[C_wt, r_wt] = nlinfit(L, Y_wt, @Fit_SingleKD, C0);
[C_m1, r_m1] = nlinfit(L, Y_m1, @Fit_SingleKD, C0);
[C_m2, r_m2] = nlinfit(L, Y_m2, @Fit_SingleKD, C0);
% Output KD values so they show up in the command window.
KD1_wt = C_wt
KD1_m1 = C_m1
KD1_m2 = C_m2
% Using the same model as in "Fit_SingleKD," we prepare a vector of
% values for the binding fraction, using the chosen ligand-space.
% Then we can compare the fit to the raw signal data.
fitY_wt = L_space./(L_space + KD1_wt);
fitY_m1 = L_space./(L_space + KD1_m1);
fitY_m2 = L_space./(L_space + KD1_m2);
% Finally, the wild-type and mutant data points and model curves are plotted.
% Try changing the legend to reflect the names of your mutants (X#Z).
figure
subplot(3,1,1)
semilogx(L, Y_wt, 'x')
hold on
semilogx(L_space, fitY_wt)
xlabel('log [L] (\mu M)')
ylabel('binding Y')
legend('wild type data', 'wild type fit')
title('Part 1: Simple KD fit')
subplot(3,1,2)
semilogx(L, Y_m1, '+')
hold on
semilogx(L_space, fitY_m1, ':')
xlabel('log [L] (\mu M)')
ylabel('binding Y')
legend('mut1 data', 'mut1 fit')
subplot(3,1,3)
semilogx(L, Y_m2, 'o')
hold on
semilogx(L_space, fitY_m2, '-')
xlabel('log [L] (\mu M)')
ylabel('binding Y')
legend('mut2 data', 'mut2 fit')
% The residuals are plotted as well, to give a sense of the accuracy
% and appropriateness of the model.
figure
semilogx(L, r_wt, 'x')
hold on
semilogx(L, r_m1, '+')
hold on
semilogx(L, r_m2, 'o')
hold on
semilogx(L_space, 0, ':')
title('Residuals from fitting binding data')
xlabel('log [L] (\mu M)')
ylabel('residual')
legend('wild type', 'mutant 1', 'mutant 2')
%% PART 2: Model for single KD plus Hill coefficient, Method 1
% We will now use the same strategy as above, but we will call a
% function that should more appropriately model the behaviour of
% inverse pericam, namely "Fit_KDn," a two-parameter model. The
% parameter KDn_x returns a value for KD as well as one for the
% Hill coefficient n. As before, r2 returns residuals.
C= [0 1];
[KDn_wt, r2_wt] = nlinfit(L, Y_wt, @Fit_KDn, C);
[KDn_m1, r2_m1] = nlinfit(L, Y_m1, @Fit_KDn, C);
[KDn_m2, r2_m2] = nlinfit(L, Y_m2, @Fit_KDn, C);
% Output KD and n values so they show up in the command window.
KD2_wt = KDn_wt(1)
n_wt = KDn_wt(2)
KD2_m1 = KDn_m1(1)
n_m1 = KDn_m1(2)
KD2_m2 = KDn_m2(1)
n_m2 = KDn_m2(2)
% Using the same model as in "Fit_KDn," we prepare a vector of
% values for the binding fraction, using the chosen ligand-space.
% Then we can compare the fit to the raw signal data.
fitY2_wt = (L_space.^n_wt)./(L_space.^n_wt + KD2_wt.^n_wt);
fitY2_m1 = (L_space.^n_m1)./(L_space.^n_m1 + KD2_m1.^n_m1);
fitY2_m2 = (L_space.^n_m2)./(L_space.^n_m2 + KD2_m2.^n_m2);
% Finally, the wild-type and mutant data points and model curves are plotted.
figure
subplot(3,1,1)
semilogx(L, Y_wt, 'x')
hold on
semilogx(L_space, fitY2_wt)
xlabel('log [L] (\mu M)')
ylabel('binding Y')
legend('wild type data', 'wild type fit')
title('Part 2: Fit for KD and n')
subplot(3,1,2)
semilogx(L, Y_m1, '+')
hold on
semilogx(L_space, fitY2_m1, ':')
xlabel('log [L] (\mu M)')
ylabel('binding Y')
legend('mut1 data', 'mut1 fit')
subplot(3,1,3)
semilogx(L, Y_m2, 'o')
hold on
semilogx(L_space, fitY2_m2, '-')
xlabel('log [L] (\mu M)')
ylabel('binding Y')
legend('mut2 data', 'mut2 fit')
% The residuals are plotted as well, to give a sense of the accuracy
% and appropriateness of the model.
figure
semilogx(L, r2_wt, 'x')
hold on
semilogx(L, r2_m1, '+')
hold on
semilogx(L, r2_m2, 'o')
hold on
semilogx(L_space, 0, ':')
title('Residuals from fitting binding data')
xlabel('log [L] (\mu M)')
ylabel('residual')
legend('wild type', 'mutant 1', 'mutant 2')
%% PART 3: Model for single KD plus Hill coefficient, Method 2
% One form of the Hill equation reads: log(Y/(1-Y)) = n log(L) - n log(KA)
% where n is the Hill coefficient, and KA is the apparent KD.
% The binding data must be transformed into a form appropriate for the
% Hill equation, namely: Y/(Y-1).
% Rather than continue to use three separate variables for everything,
% we will begin to harness the matrix manipulation capabilities of MATLAB.
% Feel free to ask questions if you have trouble following along.
Y = [Y_wt; Y_m1; Y_m2];
Yp = Y./(1-Y);
% We now convert to base-10 logarithms convenient for use with the model.
logYp = log10(Yp);
logL = log10(L);
% The following loop creates several arrays and matrices. The loop has three
% iterations, one for each protein sample. Several steps occur per iteration:
% 1. A degree-1 (linear) polynomial "p" that fits the log-log Yp vs. L data
% is determined using the least-squares function polyfit.
% 2. The outputs are explicitly re-named as intercept and slope of a model line.
% 3. The Hill coefficient and apparent KD are then calculated.
% 4. Now, the fitted values "f" are gotten using the function polyval. This
% is similar to getting the Yhat vector with nlinfit in the previous part.
% 5. Finally, the fitted values are converted back to non-logarithmic form.
% Note: colons indicate that something should be done for the entire row
% (or column, depending on placement) of a particular matrix.
for i=1:3
p(i,:) = polyfit(logL, logYp(i,:), 1);
intercept = p(i,1)
slope = p(i,2)
Hill(i) = slope
KA(i) = 10^(-intercept/Hill(i))
f(i,:) = polyval(p(i,:), logL);
Yp_fit(i,:) = 10.^(f(i,:));
end
% A figure with two plots is made.
% First, a linear plot of Y vs. L is made to show whether it is sigmoidal
% (indicating cooperativity) or asymptotic (indicating independence).
% A narrow x-axis range is used for better visibility.
figure
subplot(2,3,1)
plot(L, Y(1,:), 'x')
title('Part 3, binding plots')
%axis([0 1 0 1])
xlabel('{\it [L]} \mu M')
ylabel('binding fraction {\it y}')
subplot(2,3,2)
plot(L, Y(2,:), '+')
%axis([0 1 0 1])
xlabel('{\it [L]} \mu M')
ylabel('binding fraction {\it y}')
subplot(2,3,3)
plot(L, Y(3,:), 'o')
%axis([0 1 0 1])
xlabel('{\it [L]} \mu M')
ylabel('binding fraction {\it y}')
% Next, a log-log plot of the Yp vs. L data is overlaid with a log-log plot
% of the fitted Yp values vs. L.
subplot(2,3,4)
loglog(L, Yp(1,:), 'x')
hold on
loglog(L, Yp_fit(1,:))
title('Part 3, Hill plots')
xlabel('log_{10} {\it [L]} \mu M')
ylabel('log_{10} ({\it Y} / ({1 - {\it Y}}))')
subplot(2,3,5)
loglog(L, Yp(2,:), '+')
hold on
loglog(L, Yp_fit(2,:), ':')
xlabel('log_{10} {\it [L]} \mu M')
ylabel('log_{10} ({\it Y} / ({1 - {\it Y}}))')
subplot(2,3,6)
loglog(L, Yp(3,:), 'o')
hold on
loglog(L, Yp_fit(3,:), '-')
xlabel('log_{10} {\it [L]} \mu M')
ylabel('log_{10} ({\it Y} / ({1 - {\it Y}}))')