From 28fe9ea69e2b7daa2138b8bd6ea28bd4430b82e6 Mon Sep 17 00:00:00 2001 From: Ed Emmott Date: Sun, 4 Feb 2018 15:15:15 -0500 Subject: [PATCH] bca_PE script added --- bca_PE.m | 150 +++++++++++++++++++++++++++++++++ example_function_call_script.m | 2 + testdata_PE.csv | 82 ++++++++++++++++++ testdata_PE_analysis.csv | 6 ++ testdata_PE_scurve.pdf | Bin 0 -> 6025 bytes 5 files changed, 240 insertions(+) create mode 100644 bca_PE.m create mode 100755 testdata_PE.csv create mode 100644 testdata_PE_analysis.csv create mode 100644 testdata_PE_scurve.pdf diff --git a/bca_PE.m b/bca_PE.m new file mode 100644 index 0000000..666635c --- /dev/null +++ b/bca_PE.m @@ -0,0 +1,150 @@ +%% bca_PE script for looking at BCA results from a spectramax i3 multimode plate reader. + +% Written by Ed Emmott, Northeastern University, Boston MA, 2018. + +% Note this script is designed to work only on assay results generated +% using the standard plate format. + +% Requires: Matlab, Matlab Stats and machine learning toolbox. + +% [results, fit, data ] = bca_PE ( 'testdata_SM.csv' , 5 , 'auto' , 'Conc' , 1 , 'Vol' , 50 , 'Dil' , 5 , 'LB' , 5 ) +% +% The only required parameters are the filename and number of samples. The others are: +% * 'conc' : desired sample concentration in microgram/mL. Default is 1. +% * 'vol' : desired sample volume in microlitres. Default is 50. +% * 'dil' : dilution of your sample used for the assay. Default assumes 1 in 5 dilution. +% * 'lb' : Laemelli loading buffer concentration. Is your loading buffer 5x, 6x etc. Default is 5x. +% * 'force' : If a sample is too low concentration, force the function to give list the required amount of sample even if this means going over volume. Default is false which has the function instead scale the achievable maximum concentration down for your samples. Options True/False. +% +% The minimal call would be: +% BCA_PE('testdata_SM.csv',5) +% This would assume all the defaults given above. + +function [results,bcaFit,data] = bca_PE(filename,samples,varargin) +% parses the various optional and required inputs +p = inputParser; + +% list defaults +defaultAuto = 'auto'; % autoscales down concentration if theres an issue +validAuto = {'auto','force'}; +checkAuto = @(x) any(validatestring(x,validAuto)); + +defaultConc = 1; % 1mg/mL default +defaultVol = 50; % 50uL default +defaultDil = 5; % samples diluted 5-fold prior to assay default +defaultLB = 5; % using 5x loading buffer default + +% list inputs +addRequired(p,'filename',@ischar); +addRequired(p,'samples',@isnumeric); +addOptional(p,'auto', defaultAuto , checkAuto); +addParameter(p,'conc' , defaultConc , @isnumeric); +addParameter(p,'vol' , defaultVol , @isnumeric); +addParameter(p,'dil' , defaultDil , @isnumeric); +addParameter(p,'lb' , defaultLB , @isnumeric); + +parse(p,filename , samples , varargin{:}) + +%% Import .csv +% Modified from matlab generated import code. +delimiter = ','; +startRow = 7; +endRow = 14; + +formatSpec = '%*s%f%f%f%f%f%f%f%f%f%f%f%f%*s%[^\n\r]'; +fileID = fopen(p.Results.filename,'r','n','UTF-8'); +fseek(fileID, 3, 'bof'); + +textscan(fileID, '%[^\n\r]', startRow-1, 'WhiteSpace', '', 'ReturnOnError', false); +dataArray = textscan(fileID, formatSpec, endRow-startRow+1, 'Delimiter', delimiter, 'TextType', 'string', 'EmptyValue', NaN, 'ReturnOnError', false, 'EndOfLine', '\r\n'); +fclose(fileID); + +data = [dataArray{1:end-1}]; + +%% Remove background, calculate fit. +% calculate mean background +bg = mean(mean(data(6:8,1:2))); +% subtract background from all wells +data = data(:,:) - bg; +% concentrations of standard curve +concY = [0.125 0.25 0.5 1 2]; +% mean intensity of the standard curve +intX = [mean(data(5,1:2)) mean(data(4,1:2)) mean(data(3,1:2)) mean(data(2,1:2)) mean(data(1,1:2))]; + +bcaFit = fitlm(intX,concY); + +colNum = 3; +rowNum = 1; +results = {}; + +for i = 1:p.Results.samples + % averages duplicate readings + meanResult = mean(data( rowNum , colNum:colNum + 1 )); + % names samples + results{i,1} = strcat('Sample_',num2str(i)); + % predicts concentration and adjusts for sample dilution + results{i,2} = round(predict(bcaFit,meanResult) * p.Results.dil,2); + % if/else works through the rows and columns of the 96 well plate with increasing sample number. + if rowNum == 8 + colNum = colNum + 2; + rowNum = 1; + else + rowNum = rowNum + 1; + end +end +results = cell2table(results); + +% Amount of Loading buffer +for i = 1:p.Results.samples + results{i,3} = round(p.Results.vol / p.Results.lb,1); +end + +% Amount of Sample +for i = 1:p.Results.samples + results{i,4} = round((p.Results.vol * p.Results.conc) / results{i,2},1); +end + +% Amount of Lysis buffer to make up to volume +for i = 1:p.Results.samples + results{i,5} = round(p.Results.vol - (results{i,3} + results{i,4}),1); + % TODO: ADD ERROR HANDLING LOOP HERE FOR IF TOTAL IS -ve. +end + +results.Properties.VariableNames = {'Sample_name','Conc_in_mg_per_mL','uL_LB','uL_sample','uL_Lysis_buff'}; + +%% Rename your samples + + +%% Plot and generate pdf of results +%% +% generate short figure name +if contains(p.Results.filename,'/') == 1; + indx = strfind(p.Results.filename, '/'); + sfilename = extractAfter(p.Results.filename,indx(numel(indx))); + sfilename = extractBefore(sfilename,'.csv'); +else + sfilename = extractBefore(p.Results.filename,'.csv'); +end + +f1 = figure +%ax1 = subplot (1,2,1) + +plot(bcaFit) +title ( strcat('BCA_Assay_of_',sfilename)) +xlabel ( 'Concentration in mg/mL') +ylabel ( 'Absorbance') + +resultsString = evalc('disp(bcaFit.Rsquared)'); +resultsString = strrep(resultsString,'','\bf'); +resultsString = strrep(resultsString,'','\rm'); +resultsString = strrep(resultsString,'_','\_'); +FixedWidth = get(0,'FixedWidthFontName'); +annotation(gcf,'Textbox','String',resultsString,'Interpreter','Tex','FontName',FixedWidth,'FitBoxToText', 'on','Position',[0.68 0.25 0.2 0.16]); % these values 'work for me (TM)' + +% generate printout of plot +saveas(gcf,strcat(sfilename,'_scurve.pdf')) +% write .csv of table +writetable(results,strcat(sfilename,'_analysis.csv')) + +end + diff --git a/example_function_call_script.m b/example_function_call_script.m index cda8d33..3a6863e 100644 --- a/example_function_call_script.m +++ b/example_function_call_script.m @@ -8,3 +8,5 @@ %% Simple call with all output options [results , fit , data] = bca_SM('/Users/Ed/Documents/GitHub/BCA_assay_analysis/testdata_SM.csv',5) +%% +bca_PE('/Users/Ed/Documents/GitHub/BCA_assay_analysis/testdata_PE.csv',5) \ No newline at end of file diff --git a/testdata_PE.csv b/testdata_PE.csv new file mode 100755 index 0000000..7c2b0e1 --- /dev/null +++ b/testdata_PE.csv @@ -0,0 +1,82 @@ +Plate information +Plate,Plate Repeat,Barcode,Chamber temperature at start,Chamber temperature at end,Ambient temperature at start,Ambient temperature at end,ScanX,ScanY,Well Repeat,Measurement date,excwavelength,emswavelength,trfwindowindex +1,0,V_BC_1/22/2018 12:15:38 PM_Instr:1412121,,,,,,,1,,,, + + +Results for ABS mono + +Plate: 1, PlateRepeat: 0, WellRepeat: 1 +,1,2,3,4,5,6,7,8,9,10,11,12 +A,1.9093049050937685,1.9704030018080061,0.59130312783878825,0.552166615266548,,,,,,,, +B,1.0841976144527712,1.1114009480242988,0.8497110067378556,0.82880236182543476,,,,,,,, +C,0.64547301506379406,0.65236008692352287,0.82952908720135243,0.84973246213918352,,,,,,,, +D,0.33056893757180633,0.34614616955975364,0.8466952073782148,0.85004381201667278,,,,,,,, +E,0.25853938128948467,0.24829000795214454,1.0158142566075319,0.99055917244233238,,,,,,,, +F,0.068563483985029816,0.06675897960916502,0.94888318836627528,0.93073984013539568,,,,,,,, +G,0.069596748440471951,0.067779090803971709,0.043319132285120812,0.043203520466502145,,,,,,,, +H,0.06924614068750462,0.06965015752094407,0.043163304520765333,0.0428701968724642,,,,,,,, + +Analysis Result   + +Screen Basic Information +Software version:,,1.0 +Screen Started:,,2018-01-22T12:15:38.4649042-05:00 +Screen Finished:,,2018-01-22T12:16:13.2478937-05:00 +instrument Serial Number:,,1412121 +Protocol ID:,,143 + +Protocol Owner:,,EnSight-PC\Admin +Protocol Name:,,BCA assay + +Number of plate repeats,,1 +Start plate repeat each [s],,0 + +Plate Type +Plate Type Name:,,96 General +Number of rows:,,8 +Number of columns:,,12 +Plate Height [mm]:,,14.35 +Bottom Height [mm]:,,0 +Bottom thickness [mm]:,,0 +Well diameter (bottom) [mm]:,,6.5 +Well shape:,,Round +Volume of the well [µl]:,,300 + +Optical index:,,1.58 +Platemap +Plate +,1,2,3,4,5,6,7,8,9,10,11,12 +A,-,-,-,-,,,,,,,, +B,-,-,-,-,,,,,,,, +C,-,-,-,-,,,,,,,, +D,-,-,-,-,,,,,,,, +E,-,-,-,-,,,,,,,, +F,-,-,-,-,,,,,,,, +G,-,-,-,-,,,,,,,, +H,-,-,-,-,,,,,,,, + + + + + +Operations: + + +Measurements: + +Meas,,,, +Tech,,,,ABS mono +Exc. filter [nm],,,, +Excitation wavelength [nm],,,,562 +Measurement mode,,,,Single +Measurement height [mm],,,,7.5 +Number of flashes,,,,100 +Number of flashes integrated,,,,100 +Flash power,,,,100 + +Analysis: + + +Comments: +TimeStamp,AuthenticationType,CreatorID,Type,ProtocolID,ProtocolVersion,ScreenID,Text, + diff --git a/testdata_PE_analysis.csv b/testdata_PE_analysis.csv new file mode 100644 index 0000000..735130e --- /dev/null +++ b/testdata_PE_analysis.csv @@ -0,0 +1,6 @@ +Sample_name,Conc_in_mg_per_mL,uL_LB,uL_sample,uL_Lysis_buff +Sample_1,2.31,10,21.6,18.4 +Sample_2,3.78,10,13.2,26.8 +Sample_3,3.79,10,13.2,26.8 +Sample_4,3.83,10,13.1,26.9 +Sample_5,4.69,10,10.7,29.3 diff --git a/testdata_PE_scurve.pdf b/testdata_PE_scurve.pdf new file mode 100644 index 0000000000000000000000000000000000000000..2999f1f83e5619ee0aab9431d69ad4673d4f5124 GIT binary patch literal 6025 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