forked from ncats/RT-CETSA-Analysis
-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy patha190606_PlateSpot_TimeSeries_ForPublication220718.m
330 lines (230 loc) · 13.4 KB
/
a190606_PlateSpot_TimeSeries_ForPublication220718.m
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
%%% The analytical Matlab code in this file was developed for a biomedical
%%% research project. The results of that project were published during 2022
%%% in the ACS Chemical Biology peer-reviewed scientific journal.
%%% All reported usage of this work should cite the below published
%%% article. See journal article for description of functions in this code.
%%% Article Title: "A real-time cellular thermal shift assay (RT-CETSA) to monitor target engagement"
%%% Article Authors: Sanchez, Tino; Ronzetti, Michael; Owens, Ashley; Antony, Maria; Voss, Ty; Wallgren, Eric; Talley, Daniel; Balakrishnan, Krishna; Leyes Porello, Sebastian; Rai, Ganesha; Marugan, Juan; Michael, Samuel; Baljinnyam, Bolormaa; Southall, Noel; Simeonov, Anton; Henderson, Mark J.
%%% Journal Title: ACS Chemical Biology
%%% Year Published: 2022
clear
% set directory that contains input tif files from time lapse imaging
InputDir = uigetdir
cd(InputDir)
% this sets size of region in image that will be measured
% for each individual sample within the grid/plate layout, modify if plate
% or instrument set-up is changed
SizeRegionPerWell_x = 40;
SizeRegionPerWell_y = 40;
% opens first image in the time series, allows image parameters to be determined
% file name can be changed if needed, ie: systematic naming convention
% changes for another instrument
Im_1 = imread('1.tif');
% determines if image is RGB format grayscale (3x 8-bit channels).
% extracts 1 channel for further analysis
if size(Im_1, 3) > 1
Im_1 = Im_1(:,:,1);
end
% find im values for display
Im_1_PixInt_Min = min(Im_1(:));
Im_1_PixInt_Max = max(Im_1(:));
% user selects points to define grid layout
h_f1 = figure, imshow(Im_1,[])
uiwait(msgbox('select center of upper left well with mouse then hit enter', 'modal'))
[UL_x,UL_y] = getpts(h_f1)
uiwait(msgbox('select center of upper right well with mouse then hit enter', 'modal'))
[UR_x, UR_y] = getpts(h_f1)
uiwait(msgbox('select center of lower right well with mouse then hit enter', 'modal'))
[LR_x, LR_y] = getpts(h_f1)
% plot points for confirmation
Im_1_points = false(size(Im_1));
Im_1_points(uint16(UL_y),uint16(UL_x))=1;
Im_1_points(uint16(UR_y),uint16(UR_x))=1;
Im_1_points(uint16(LR_y),uint16(LR_x))=1;
% figure, imshow(Im_1_points,[]), title('selected corner points')
PlateChoice_List = {'96 well','384 well','1536 well'};
[PlateChoice_Index,PlateChoice_tf] = listdlg('ListString',PlateChoice_List,'PromptString',{'Select your plate type.',''},'SelectionMode','single');
% NumTotalCol = 24;
% NumTotalRow = 16;
NumTotalCol_List = [12; 24; 48];
NumTotalCol_First = 1;
NumTotalCol_Last = NumTotalCol_List(PlateChoice_Index);
NumTotalRow_List = [8; 16; 32];
NumTotalRow_First = 1;
NumTotalRow_Last = NumTotalRow_List(PlateChoice_Index);
prompt = {'Enter first row coordinate selected:','Enter first column coordinate selected:','Enter last row coordinate selected:','Enter last column coordinate selected:'};
dlgtitle = 'Input';
dims = [1 35];
definput = {num2str(NumTotalRow_First), num2str(NumTotalCol_First), num2str(NumTotalRow_Last), num2str(NumTotalCol_Last)};
answer_PlateCoord = inputdlg(prompt,dlgtitle,dims,definput);
NumTotalRow_First = str2num(cell2mat(answer_PlateCoord(1)));
NumTotalCol_First = str2num(cell2mat(answer_PlateCoord(2)));
NumTotalRow_Last = str2num(cell2mat(answer_PlateCoord(3)));
NumTotalCol_Last = str2num(cell2mat(answer_PlateCoord(4)));
Tif_File_List_1 = ls ('*.tif');
% number of timepoints based on number of image files in time series.
Num_TimePoints = size(Tif_File_List_1,1);
OutputNumbers_MeanInt_Uncorrected = uint16(zeros(((NumTotalCol_Last-NumTotalCol_First)*(NumTotalRow_Last-NumTotalRow_First)),Num_TimePoints));
OutputNumbers_MeanInt_SubtractBG = OutputNumbers_MeanInt_Uncorrected;
Mask_Outline_Single = false(SizeRegionPerWell_y+1,SizeRegionPerWell_x+1);
Mask_Outline_Single(:,1)=1;
Mask_Outline_Single(:,end)=1;
Mask_Outline_Single(1,:)=1;
Mask_Outline_Single(end,:)=1;
% loop for time points
for Count_Time = 1:Num_TimePoints
% Count_Time = 1;
Count_Time
Output_PlateLayout_1 = uint16(zeros(NumTotalRow_List(PlateChoice_Index),NumTotalCol_List(PlateChoice_Index)));
myfilename = sprintf('%d.tif', Count_Time);
Im_1 = imread(myfilename);
% determines if image is RGB format grayscale (3x 8-bit channels).
% extracts 1 channel for further analysis
if size(Im_1,3) > 1
Im_1 = Im_1(:,:,1);
end
% set output couter to zero for each grid position (biological sample)
Count_Output = 0;
% increase size of points for display of central well region position on image
Im_1_points_dil = imdilate(Im_1_points, strel('disk',1));
% figure, imshow(Im_1_points_dil,[])
% y scale is backward becuase it is an image, flips sign of slope
Line_UL_UR_slope = (UL_y - UR_y) / (UL_x - UR_x);
Line_UL_UR_degrees = atand(Line_UL_UR_slope);
% corrects for any rotation of the image,
% based on user selected sample positions
Im_2 = imrotate(Im_1, Line_UL_UR_degrees);
% figure, imshow(Im_2,[Im_1_PixInt_Min Im_1_PixInt_Max])
% create temp image that can later be used
% for well center visualization, useful for confirmation or debugging
test1 = Im_2;
Im_2_points_dil = imrotate(Im_1_points_dil, Line_UL_UR_degrees);
% figure, imshow(Im_2_points_dil,[])
Im_2_points_dil_L = bwlabel(Im_2_points_dil);
Im_2_points_props = regionprops(Im_2_points_dil_L, 'Centroid');
% the below values should be left as floating point format...
% warning: loss of precision. should convert to integer at last step
% Rotated_WellCenters_XY =
% reshape([Im_2_points_props.Centroid],[size(Im_2_points_props,1),2]);
% wrong format above
Rotated_WellCenters_XY = reshape([Im_2_points_props.Centroid],[2,size(Im_2_points_props,1)])'; % correct matrix fomat for paired xy points
% Rotated_WellCenters_PerPlate_Xmin = (Im_2_points_props(1).Centroid(1));
% Rotated_WellCenters_PerPlate_Xmax = (Im_2_points_props(2).Centroid(1));
Rotated_WellCenters_PerPlate_Xmin = min(Rotated_WellCenters_XY(:,1));
Rotated_WellCenters_PerPlate_Xmax = max(Rotated_WellCenters_XY(:,1));
Rotated_WellCenters_PerPlate_Xdist = Rotated_WellCenters_PerPlate_Xmax - Rotated_WellCenters_PerPlate_Xmin;
Rotated_WellDistance_X = Rotated_WellCenters_PerPlate_Xdist / ((NumTotalCol_Last - NumTotalCol_First));
% Rotated_WellCenters_PerPlate_Ymin = (Im_2_points_props(1).Centroid(2));
% Rotated_WellCenters_PerPlate_Ymax = (Im_2_points_props(3).Centroid(2));
Rotated_WellCenters_PerPlate_Ymin = min(Rotated_WellCenters_XY(:,2));
Rotated_WellCenters_PerPlate_Ymax = max(Rotated_WellCenters_XY(:,2));
Rotated_WellCenters_PerPlate_Ydist = Rotated_WellCenters_PerPlate_Ymax - Rotated_WellCenters_PerPlate_Ymin;
Rotated_WellDistance_Y = Rotated_WellCenters_PerPlate_Ydist / ((NumTotalRow_Last - NumTotalRow_First));
SizeRegionPerWell_x_HalfDist = (SizeRegionPerWell_x/2);
SizeRegionPerWell_y_HalfDist = (SizeRegionPerWell_y/2);
Mask_Outline_All = uint8(zeros(size(Im_2)));
Count_Well_Per_Time = 0;
CountRow = 0;
CountCol = 0;
for C1 = NumTotalRow_First:NumTotalRow_Last % sample grid row loop
% C1 = 1
% C1
CountRow = CountRow + 1;
for C2 = NumTotalCol_First:NumTotalCol_Last % sample grid column loop
% C2 = 10
% C2
CountCol = CountCol + 1;
Count_Well_Per_Time = Count_Well_Per_Time + 1;
SingleWell_Center_X = uint16(((C2-1)*Rotated_WellDistance_X) + Rotated_WellCenters_PerPlate_Xmin);
SingleWell_Center_Y = uint16(((C1-1)*Rotated_WellDistance_Y) + Rotated_WellCenters_PerPlate_Ymin);
% test1 = Im_2;
test1(uint16(SingleWell_Center_Y), uint16(SingleWell_Center_X)) = 40000;
% 2018b
% h_ROI = images.roi.Rectangle(gca,'Position',[(SingleWell_Center_X - SizeRegionPerWell_x_HalfDist),(SingleWell_Center_Y - SizeRegionPerWell_y_HalfDist),SizeRegionPerWell_x,SizeRegionPerWell_y],'StripeColor','r');
% Extract single sample region and convert to 16 bit: makes data consistent across different
% input types
Im_2_SingleWell = Im_2(uint16((SingleWell_Center_Y - SizeRegionPerWell_y_HalfDist)):uint16((SingleWell_Center_Y + SizeRegionPerWell_y_HalfDist)), uint16((SingleWell_Center_X - SizeRegionPerWell_x_HalfDist)):uint16((SingleWell_Center_X + SizeRegionPerWell_x_HalfDist)));
% figure, imshow(Im_2_SingleWell,[]), title(strcat('r', num2str(CountRow), ' ', 'c', num2str(CountCol)))
% median filter to reduce outlier pixels prior to
% thresholding
Im_2_SingleWell_MedFilt = medfilt2(Im_2_SingleWell,[5 5], 'symmetric');
% figure, imshow(Im_2_SingleWell_MedFilt,[])
% threshold local region
[Thrsh,Thrsh_EM] = graythresh(Im_2_SingleWell_MedFilt);
% select lowest 5% of pixels, then measure median to estimate
% local background
BG_x1 = sort(Im_2_SingleWell_MedFilt);
BG_x2 = BG_x1(1:uint16(size(BG_x1,1)/20));
BG_x3 = median(BG_x2(:));
if Count_Well_Per_Time == 1 % set this on first time point only
BG_Well_perTime(Count_Well_Per_Time,1) = BG_x3;
end
% incremental counter for each sample position (row column combination)
Count_Output = Count_Output + 1;
OutputNumbers(Count_Output,1) = C1; % well row coord
OutputNumbers(Count_Output,2) = C2; % well column coord
% OutputNumbers(Count_Output,3) = Mask_Area;
% OutputNumbers(Count_Output,4) = Mask_MeanInt_Uncorrected;
% OutputNumbers(Count_Output,5) = BG_MeanInt;
% OutputNumbers(Count_Output,6) = Mask_MeanInt_SubtractBG;
OutputNumbers_MeanInt_Uncorrected(Count_Output,Count_Time) = mean(Im_2_SingleWell(:));
% OutputNumbers_MeanInt_SubtractBG(Count_Output,Count_Time) = Mask_MeanInt_SubtractBG;
OutputNumbers_MeanInt_SubtractBG(Count_Output,Count_Time) = mean(Im_2_SingleWell(:))-BG_x3;
OutputNumbers_BG(Count_Output,Count_Time)=BG_x3;
% Mask_Outline_Single = bwperim(Mask_2);
% Mask_Outline_Single = true(size(Im_2_SingleWell));
Mask_Outline_Single_FullField = false(size(Im_2));
Mask_Outline_Single_FullField(((SingleWell_Center_Y - SizeRegionPerWell_y_HalfDist)):uint16((SingleWell_Center_Y + SizeRegionPerWell_y_HalfDist)), uint16((SingleWell_Center_X - SizeRegionPerWell_x_HalfDist)):uint16((SingleWell_Center_X + SizeRegionPerWell_x_HalfDist))) = Mask_Outline_Single;
Mask_Outline_All(Mask_Outline_Single_FullField == 1) = 200;
% end % end conditional for threshold quality
end % end C2 Column Loop
end % C1 Row Loop
% figure, imshow(Mask_Outline_All,[])
% for visualizing/debugging sample center positions
test1 = imdilate(test1, strel('disk',3));
% imshow(test1,[min(Im_1(:)) max(Im_1(:))]), title(strcat('TimePoint ',num2str(Count_Time)))
% for display
ScaleInt = double(max(Im_2(:))-median(BG_Well_perTime(:)))/256;
Im_2_NoBG = Im_2 - double(median(BG_Well_perTime(:)));
Im_2_NoBG_8bit = uint8(Im_2_NoBG/ScaleInt);
% figure, imshow(Im_2_NoBG_8bit,[])
% for display
Im_2_RegionOverlay = uint8(Mask_Outline_All);
Im_2_RegionOverlay(:,:,2)=Im_2_NoBG_8bit;
Im_2_RegionOverlay(:,:,3) = 0;
imshow(Im_2_RegionOverlay,[])
end % end loop for time points
% concatenate well coordinates with measurements
% % OutputList_SortedByTime = [OutputNumbers(:,1:2),OutputNumbers_MeanInt_SubtractBG];
% % OutputList_SortedByTime = [OutputNumbers(:,1:2),OutputNumbers_MeanInt_Uncorrected];
% % OutputList_SortedByTime = [OutputNumbers(:,1:2),OutputNumbers_BG];
% correct background based on first time point in the time series
OutputNumbers_SubtractSingleBG = double(OutputNumbers_MeanInt_Uncorrected) - double(median(BG_Well_perTime(:)));
% For output, combine sample row column coordinates with background subtracted results
OutputList_SortedByTime = [OutputNumbers(:,1:2),OutputNumbers_SubtractSingleBG];
% save output as excel file in same directory as input files
Filename = 'MatlabResults_1.xlsx';
writematrix(OutputList_SortedByTime, Filename,'FileType','spreadsheet')
%
%copy above text to analyze plate
%
%%% use below commented code to initially compare results for samples
%%% Plot curves for 2 wells
% Plot_Well_1_Coord_Row = 2
% Plot_Well_1_Coord_Col = 1
%
% Plot_Well_2_Coord_Row = 5
% Plot_Well_2_Coord_Col = 3
%
% Plot_Well_1_Idx = find(OutputList_SortedByTime(:,1) == Plot_Well_1_Coord_Row & OutputList_SortedByTime(:,2) == Plot_Well_1_Coord_Col);
% Plot_Well_2_Idx = find(OutputList_SortedByTime(:,1) == Plot_Well_2_Coord_Row & OutputList_SortedByTime(:,2) == Plot_Well_2_Coord_Col);
%
% y1 = OutputList_SortedByTime(Plot_Well_1_Idx,3:end)';
% y2 = OutputList_SortedByTime(Plot_Well_2_Idx,3:end)';
% x1 = 1:size(y1,1)';
%
% figure
% plot(x1,y1)
% hold on
% plot(x1,y2)
% legend(gca,'show');