Skip to content
Permalink
master
Switch branches/tags

Name already in use

A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?
Go to file
 
 
Cannot retrieve contributors at this time
function spectraViewer
% Viewer for excitation and emission spectra of fluorescent dyes
%
% Data organization inside spectra files:
% All files are expected to be comma separated lists without header.
% Data are expected to be (in this order):
% Wavelength (abs), Absorption coef, Wavelength (em), Emission coef,
% Wavelength (2p), 2p cross section, Wavelength (3p), 3p cross section.
% If there are no 2p and/or 3p cross section data the files should only
% contain 4 or 6 columns.
%
% Convert Excel files to csv files:
% - Make sure the excel sheet uses '.' as a decimal separator. If not, go
% to File -> Options -> Advanced -> Editing options -> Use system separator
% and change accordingly. Then, go to File -> Export -> Change File Type ->
% CSV -> Save as and save file. The region settings of your OS might result
% in semicolon-separated lists (instead of comma-separated lists). If so,
% go to Windows Start menu - Region and language - Additional settings -
% List separator and set it to comma.
%
% Use https://apps.automeris.io/wpd/ to digitize plots in figures. Save as
% csv file, and import in excel to combine various properties (Excel: Data
% - Get External Data: From text. Make sure "Data format" is "Text" for all columns!)
%
% Spectra of light sources and filters:
% Spectra of light sources and/or filter can be selected and displayed from
% the Light sources and filter menu. These are assumed to be csv files with
% two columns (wavelength, transmission/intensity). In order to avoid
% problems with the fluroescence spectra (which assume at least four columns)
% these spectra are saved in a subfolder "LightSources+Filter". Data sources
% are documented in the same Excel file but in a different sheet (sheets
% are named accordingly). These spectra are for now only displayed in the
% 1D viewer.
%
% Resources for spectra:
% Chroma: https://www.chroma.com/spectra-viewer (very broad spectra, not searchable)
% Semrock: https://searchlight.semrock.com/ (searchable, also light sources and filter)
% Thermofisher: http://www.thermofisher.com/de/de/home/life-science/cell-analysis/labeling-chemistry/fluorescence-spectraviewer.html
% U of Arizona: http://spectra.arizona.edu/
%
% !!! When you add or update spectra please note the source of the data in the excel
% sheet Sources.xlsx!!!
% Please indicate in the filename whether the file contains 2P and 3P cross
% sections (_2P and/or _3P after the file name). This is useful for
% filtering the list of fluorophores.
%
% Stephan Junek, 2018
% To Do!!!
% Wavelengths in RGB values from 351 nm to 750 nm
% Values calculated using https://de.mathworks.com/matlabcentral/fileexchange/7021-spectral-and-xyz-color-functions
% whos information are based on published color matching functions
wavelengthScale = 351:750;
wavelength2RGB = [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 2 2 3 4 5 7 9 11 15 19 24 30 38 47 56 66 77 88 100 113 126 139 153 167 182 196 212 227 242 257 273 287 302 315 328 341 353 364 375 385 395 403 411 417 423 427 431 434 436 437 438 439 439 439 437 435 431 427 421 414 406 396 385 373 359 343 325 305 281 252 216 171 110 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 71 259 356 430 492 547 596 642 684 723 761 796 830 862 894 925 954 983 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 988 969 950 931 912 893 874 855 836 817 798 779 760 741 723 704 686 668 650 633 616 599 582 566 550 534 518 503 488 473 459 445 431 417 403 390 378 365 353 341 330 319 308 297 286 276 267 257 248 239 230 221 213 205 197 190 182 175 168 161 155 148 142 136 130 125 119 114 109 104 99 94 90 85 81 77 73 69 65 62 58 55 51 48 45 42 39 36 34 31 29 27 25 24 22 20 19 18 16 15 14 13 12 12 11 10 9 9 8; 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 87 177 231 273 309 342 374 404 434 464 493 520 544 567 588 607 625 641 658 674 689 705 721 737 752 767 780 793 805 816 825 836 848 861 874 887 900 913 925 937 948 960 971 982 993 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 987 974 961 947 932 918 902 887 871 855 839 823 807 790 773 755 737 719 700 681 661 641 621 600 578 557 534 511 488 463 438 413 386 358 329 298 264 227 184 130 40 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0;0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 2 3 4 5 7 9 13 17 23 31 41 52 65 79 94 110 128 147 167 189 212 237 263 291 321 352 384 418 453 489 526 565 604 645 685 727 768 810 850 891 930 969 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 986 958 930 902 874 846 819 792 766 740 715 690 665 639 614 588 562 536 511 487 463 438 412 384 355 323 289 252 209 157 85 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]/1000;
% Variables
strIdxDye = [];
currData = [];
currFilt = [];
% Find folder containing the data files
pn = which('spectraViewer.m');
[pn, ~,~] = fileparts(pn);
%Find files
fn = dir([pn filesep '*.csv']);
% Add by name instead
[sortFn, sortIdx] = sort(lower({fn(:).name}));
fn = fn(sortIdx);
% Add names to structure
nDyes = numel(fn);
for f = 1:nDyes
spectra(f).name = fn(f).name;
end
% Make selection GUI
guiSz = [100 274 650 626];
gui = figure('Position',guiSz, 'Toolbar','none', 'CloseRequestFcn', @closeGui , 'Resize','off', 'Name','SpectraViewer (GUI)', 'NumberTitle','off');
% Dye-selection panel
dyeSelSz = [20 guiSz(4)/2+10 guiSz(3)-40 guiSz(4)/2-20];
dyeSel = uipanel(gui,'Title','Fluorophores','FontSize',12,...
'BackgroundColor','white','units','pixel',...
'Position',dyeSelSz, 'BackgroundColor', get(gui, 'COlor'));
nRowsDye = 0;
plusIconDye = uicontrol('Parent',dyeSel,'units','pixel','Style', 'pushbutton', 'Position', [10 dyeSelSz(4)-70 17 17], 'String', '+', 'Tooltip', 'Add dye entry', ...
'Callback', {@makeNewRow,nRowsDye});
dyeHandles = [];
uicontrol('Parent',dyeSel,'Style','Text', 'Position',[ 5, dyeSelSz(4)-50, 30, 17],'String', 'Add', 'HorizontalAlignment','center','FontWeight','bold')
uicontrol('Parent',dyeSel,'Style','Text', 'Position',[35, dyeSelSz(4)-50, 30, 17],'String', 'Del', 'HorizontalAlignment','center','FontWeight','bold')
uicontrol('Parent',dyeSel,'Style','Text', 'Position',[63, dyeSelSz(4)-50, 35, 17],'String', 'Show', 'HorizontalAlignment','center','FontWeight','bold')
uicontrol('Parent',dyeSel,'Style','Text', 'Position',[95, dyeSelSz(4)-50, 90, 17],'String', 'Selection filter', 'HorizontalAlignment','center','FontWeight','bold')
uicontrol('Parent',dyeSel,'Style','Text', 'Position',[265, dyeSelSz(4)-50, 100, 17],'String', 'Fluorophore', 'HorizontalAlignment','center','FontWeight','bold')
uicontrol('Parent',dyeSel,'Style','Text', 'Position',[395, dyeSelSz(4)-50, 40, 17],'String', '1pExc', 'HorizontalAlignment','center','FontWeight','bold')
uicontrol('Parent',dyeSel,'Style','Text', 'Position',[435, dyeSelSz(4)-50, 40, 17],'String', '2pExc', 'HorizontalAlignment','center','FontWeight','bold')
uicontrol('Parent',dyeSel,'Style','Text', 'Position',[475, dyeSelSz(4)-50, 40, 17],'String', '3pExc', 'HorizontalAlignment','center','FontWeight','bold')
uicontrol('Parent',dyeSel,'Style','Text', 'Position',[515, dyeSelSz(4)-50, 40, 17],'String', 'Em', 'HorizontalAlignment','center','FontWeight','bold')
uicontrol('Parent',dyeSel,'Style','Text', 'Position',[555, dyeSelSz(4)-50, 40, 17],'String', 'Line', 'HorizontalAlignment','center','FontWeight','bold')
% Filters and lasers
filterSelSz = [20 20 guiSz(3)-40 guiSz(4)/2-20];
filterSel = uipanel(gui,'Title','Filters and light sources','FontSize',12,...
'BackgroundColor','white','units','pixel',...
'Position',filterSelSz, 'BackgroundColor', get(gui, 'COlor'));
nRowsFilt = 0;
plusIconFilt = uicontrol('Parent',filterSel,'units','pixel','Style', 'pushbutton', 'Position', [10 filterSelSz(4)-70 17 17], 'String', '+', 'Tooltip', 'Add filter entry', ...
'Callback', {@makeNewFiltRow,nRowsFilt});
filtTypeStr = {'Excitation filter';'Emission filter';'Laser'; 'Spectrum'}; % Maybe to add: light source - selection of spectrum from file
filtHandles = [];
uicontrol('Parent',filterSel,'Style','Text', 'Position',[ 5, filterSelSz(4)-50, 30, 17],'String', 'Add', 'HorizontalAlignment','center','FontWeight','bold')
uicontrol('Parent',filterSel,'Style','Text', 'Position',[35, filterSelSz(4)-50, 30, 17],'String', 'Del', 'HorizontalAlignment','center','FontWeight','bold')
uicontrol('Parent',filterSel,'Style','Text', 'Position',[63, filterSelSz(4)-50, 35, 17],'String', 'Show', 'HorizontalAlignment','center','FontWeight','bold')
uicontrol('Parent',filterSel,'Style','Text', 'Position',[115, filterSelSz(4)-50, 90, 17],'String', 'Type', 'HorizontalAlignment','center','FontWeight','bold')
uicontrol('Parent',filterSel,'Style','Text', 'Position',[245, filterSelSz(4)-50, 100, 17],'String', 'Wavelength [nm]', 'HorizontalAlignment','center','FontWeight','bold')
uicontrol('Parent',filterSel,'Style','Text', 'Position',[365, filterSelSz(4)-50, 100, 17],'String', 'Bandwidth [nm]', 'HorizontalAlignment','center','FontWeight','bold')
makeNewFiltRow(0,0,1);
% 1D figure
fig1D = figure('Position',[780 274 850 600], 'CloseRequestFcn', @closeGui, 'Name','SpectraViewer (1D Viewer)', 'NumberTitle','off');
set(gcf,'Color','k')
axLambda = subplot(10,1,1);
imagesc( wavelengthScale([1 end]),[0 1], permute(wavelength2RGB,[3 2 1]));
axis off
set(axLambda, 'XTickLabel', '', 'YTickLabel','')
title('Spectra viewer 1D', 'Color','w')
ax1D = subplot(10,1,3:10);
linkaxes([axLambda, ax1D], 'x')
xlabel('wavelength [nm]')
ylabel('normalized abs / em')
box on
set(ax1D, 'XLim', [350 800], 'YLim',[ -0.1 1.05], 'XColor','w','YColor','w','Color',0.3*[1 1 1])
hold on
% 2D figure
fig2D = figure('Position',[1650 274 850 600], 'CloseRequestFcn', @closeGui, 'Name','SpectraViewer (2D Viewer)', 'NumberTitle','off');
set(gcf,'Color','k')
axLambdaX = subplot(10,10,1:9);
imagesc( wavelengthScale([1 end]),[0 1], permute(wavelength2RGB,[3 2 1]));
axis off
set(axLambdaX, 'XTickLabel', '', 'YTickLabel','')
title('Spectra viewer 2D', 'Color','w')
axLambdaY = subplot(10,10,20:10:100);
imagesc([0 1],wavelengthScale([end 1]), flip(permute(wavelength2RGB,[2 3 1]),1));
axis off
set(axLambdaY, 'XTickLabel', '', 'YTickLabel','', 'YDir','normal')
axIdx = reshape(1:100,[10 10]);
axIdx(10,:) = [];
axIdx(:,1) = [];
ax2D = subplot(10,10,axIdx(:));
set(ax2D, 'XLim', [350 800], 'YLim',[350 800], 'XColor','w','YColor','w','Color',0.3*[1 1 1])
xlabel('exc wavelength [nm]')
ylabel('em wavelength [nm]')
box on
linkaxes([axLambdaX, ax2D], 'x')
linkaxes([axLambdaY, ax2D], 'y')
hold on
makeNewDyeRow(0,0,1);
function makeNewDyeRow(~,~,idx)
% Delete button
dyeHandles(1,idx) = uicontrol('Parent',dyeSel,'Style', 'pushbutton', 'Position', [40 dyeSelSz(4)-(idx+2.5)*20 17 17], 'String', '-', 'Tooltip', 'Remove dye entry', 'Callback', {@deleteRow,idx,'dye'});
% Show / hide checkbox
dyeHandles(2,idx) = uicontrol('Parent',dyeSel,'Style', 'checkbox', 'Position', [70 dyeSelSz(4)-(idx+2.5)*20 17 17], 'Value',1, 'Tooltip', 'Hide dye entry', 'callback', @updatePlots);
% Filter field
dyeHandles(3,idx) = uicontrol('Parent',dyeSel,'Style', 'edit', 'Position', [100 dyeSelSz(4)-(idx+2.5)*20 80 17], 'String','', 'Tooltip', 'Filter by string', 'Callback', {@filterDyeList,idx});
% Dye popup list
dyeHandles(4,idx) = uicontrol('Parent',dyeSel,'Style', 'popup ', 'Position', [200 dyeSelSz(4)-(idx+2.5)*20 200 17], 'String',{spectra(:).name}, 'Tooltip', 'List of available fluorophors', 'Callback', {@updateDyeSelection,idx});
% 1p exc
dyeHandles(5,idx) = uicontrol('Parent',dyeSel,'Style', 'checkbox', 'Position', [410 dyeSelSz(4)-(idx+2.5)*20 17 17], 'Value',1, 'Tooltip', 'Show 1p exc' , 'callback', @updatePlots);
% Emission
dyeHandles(6,idx) = uicontrol('Parent',dyeSel,'Style', 'checkbox', 'Position', [530 dyeSelSz(4)-(idx+2.5)*20 25 17], 'Value',1, 'Tooltip', 'Show emission', 'callback', @updatePlots );
% 2p exc
dyeHandles(7,idx) = uicontrol('Parent',dyeSel,'Style', 'checkbox', 'Position', [450 dyeSelSz(4)-(idx+2.5)*20 17 17], 'Value',0, 'Tooltip', 'Show 2p exc' , 'callback', @updatePlots);
% 3p exc
dyeHandles(8,idx) = uicontrol('Parent',dyeSel,'Style', 'checkbox', 'Position', [490 dyeSelSz(4)-(idx+2.5)*20 17 17], 'Value',0, 'Tooltip', 'Show 3p exc', 'callback', @updatePlots );
% Linestyle
dyeHandles(9,idx) = uicontrol('Parent',dyeSel,'Style', 'text', 'Position', [555 dyeSelSz(4)-(idx+2.5)*20 40 17], 'String','', 'BackgroundColor',0.3*[1 1 1],'HorizontalAlignment','center', 'Tooltip', 'Plot line style' );
nRowsDye = nRowsDye + 1;
strIdxDye{idx} = 1:nDyes;
set(plusIconDye,'Callback', {@makeNewDyeRow,nRowsDye+1});
if nRowsDye == 1
set(dyeHandles(1,1), 'Enable','off');
else
set(dyeHandles(1,1), 'Enable','on');
end
updateDyeSelection(dyeHandles(4,idx),0,idx);
end
function makeNewFiltRow(~,~,idx)
% Delete button
filtHandles(1,idx) = uicontrol('Parent',filterSel,'Style', 'pushbutton', 'Position', [40 filterSelSz(4)-(idx+2.5)*20 17 17], 'String', '-', 'Tooltip', 'Remove filter entry', 'Callback', {@deleteRow,idx,'filt'});
% Show / hide checkbox
filtHandles(2,idx) = uicontrol('Parent',filterSel,'Style', 'checkbox', 'Position', [70 filterSelSz(4)-(idx+2.5)*20 17 17], 'Value',1, 'Tooltip', 'Hide filter entry', 'callback', @updateFiltObj);
% Filter type selection
filtHandles(3,idx) = uicontrol('Parent',filterSel,'Style', 'popup ', 'Position', [100 filterSelSz(4)-(idx+2.5)*20 120 17], 'String',filtTypeStr, 'Tooltip', 'Select type', 'Callback', {@setFiltType,idx});
% Wavelength
filtHandles(4,idx) = uicontrol('Parent',filterSel,'Style', 'edit', 'Position', [245 dyeSelSz(4)-(idx+2.5)*20 100 17], 'String','', 'Tooltip', 'Enter wavelength', 'Callback', {@updateFilterSelection,idx}, 'Visible','off');
% Wavelength
filtHandles(5,idx) = uicontrol('Parent',filterSel,'Style', 'edit', 'Position', [365 dyeSelSz(4)-(idx+2.5)*20 100 17], 'String','', 'Tooltip', 'Enter bandwidth', 'Callback', {@updateFilterSelection,idx}, 'Visible','off');
% Spectrum file selection
filtHandles(6,idx) = uicontrol('Parent',filterSel,'Style', 'pushbutton', 'Position', [245 dyeSelSz(4)-(idx+2.5)*20 100 17], 'String','Select file', 'Tooltip', 'Select file containing spectral information', 'Callback', {@loadSpectrum,idx}, 'Visible','off');
% Spectrum file name
filtHandles(7,idx) = uicontrol('Parent',filterSel,'Style', 'text', 'Position', [365 dyeSelSz(4)-(idx+2.5)*20 200 17], 'String','---', 'Tooltip', 'File name', 'Visible','off','HorizontalAlignment','left');
currFilt(idx).handle1D = [];
currFilt(idx).handle2D = [];
nRowsFilt = nRowsFilt + 1;
set(plusIconFilt,'Callback', {@makeNewFiltRow,nRowsFilt+1});
if nRowsFilt == 1
set(filtHandles(1,1), 'Enable','off');
else
set(filtHandles(1,1), 'Enable','on');
end
end
% Remove fluorophore row
function deleteRow(~,~,idx,dyeFilt)
switch dyeFilt
case 'dye'
hdls = dyeHandles;
nEl = nRowsDye;
data = currData;
case 'filt'
hdls = filtHandles;
nEl = nRowsFilt;
data = currFilt;
end
% Remove data entry from currData structure
keepIdx = 1:nEl;
keepIdx(idx) = [];
data = data(keepIdx);
% Remove uicontrol elements
delete(hdls(:,idx));
% Move and update remaining uicontrol elements
if idx < nEl
for ii = idx+1:nEl
for h = 1:size(hdls,1)
set(hdls(h,ii), 'Position', get(hdls(h,ii), 'Position') + [0 20 0 0]);
cb = get(hdls(h,ii), 'Callback');
if numel(cb)>1
if h == 1
set(hdls(h,ii), 'Callback', {cb{1},ii-1,dyeFilt});
else
set(hdls(h,ii), 'Callback', {cb{1},ii-1});
end
end
end
end
end
% Remove handles of uicontrol
hdls(:,idx) = [];
nEl = nEl - 1;
% Disable "Delete" button if only one row remains
if nEl == 1
set(hdls(1,1), 'Enable','off');
else
set(hdls(1,1), 'Enable','on');
end
switch dyeFilt
case 'dye'
dyeHandles= hdls;
nRowsDye = nEl;
currData = data;
set(plusIconDye,'Callback', {@makeNewDyeRow,nEl+1});
case 'filt'
filtHandles = hdls;
nRowsFilt = nEl;
currFilt = data;
set(plusIconFilt,'Callback', {@makeNewFiltRow,nEl+1});
end
updatePlots;
end
% Apply string-filter to dyes shown in popup menu
function filterDyeList(~,~,idx)
str = get(dyeHandles(3,idx), 'String');
strIdxDye{idx} = find(contains({spectra(:).name},str,'IgnoreCase',true));
if isempty(strIdxDye{idx})
set(dyeHandles(4,idx),'Value',1, 'String', 'No dye found', 'Enable','off');
else
set(dyeHandles(4,idx),'Value',1, 'String', {spectra(strIdxDye{idx}).name}, 'Enable','on');
end
end
% Switch between different selection in "Filters and lasers" GUI
function setFiltType(~,~,idx)
v = get(filtHandles(3,idx),'Value');
switch v
case 1
set(filtHandles([4 5],idx),'Visible','on');
set(filtHandles([6 7],idx),'Visible','off');
currFilt(idx).type = 'excitation';
case 2
set(filtHandles([4 5],idx),'Visible','on');
set(filtHandles([6 7],idx),'Visible','off');
currFilt(idx).type = 'emission';
case 3
set(filtHandles(4,idx),'Visible','on');
set(filtHandles(5,idx),'Visible','off');
currFilt(idx).type = 'laser';
case 4
set(filtHandles([6 7], idx), 'Visible', 'on');
currFilt(idx).type = 'spectrum';
end
end
% Update gui elements after dye selection
function updateDyeSelection(co,~,idx)
popupIdx = get(co, 'Value');
readData(idx, strIdxDye{idx}(popupIdx));
set(dyeHandles([7 8],idx), 'Value',0,'Enable', 'on');
if size(currData(idx).data,2) == 4
set(dyeHandles([7 8],idx), 'Value',0,'Enable', 'off');
elseif size(currData(idx).data,2) == 6
set(dyeHandles(8,idx), 'Value',0,'Enable', 'off');
end
updatePlots;
end
% Read spectral data from csv files and add to data structure
function readData(rowIdx, dyeIdx)
currData(rowIdx).filename = spectra(dyeIdx).name;
currData(rowIdx).data = csvread([pn filesep spectra(dyeIdx).name]);
% Exclude data that are zero (set to NaN)
for jj = 1:(size(currData(rowIdx).data,2)/2)
zeroIdx = min(currData(rowIdx).data(:,[jj*2-1 jj*2]),[],2) == 0;
currData(rowIdx).data(zeroIdx,jj*2-1:jj*2) = NaN;
end
currData(rowIdx).dyeIdx = dyeIdx;
currData(rowIdx).lambdaMax1pExc = currData(rowIdx).data(find(currData(rowIdx).data(:,2)==max(currData(rowIdx).data(:,2)),1),1);
currData(rowIdx).lambdaMaxEm = currData(rowIdx).data(find(currData(rowIdx).data(:,4)==max(currData(rowIdx).data(:,4)),1),3);
basenameIdx = strfind(currData(rowIdx).filename,'_');
if isempty(basenameIdx)
currData(rowIdx).dyeName = currData(rowIdx).filename(1:end-4);
else
currData(rowIdx).dyeName = currData(rowIdx).filename(1:basenameIdx(1)-1);
end
% Use darker version of emission color for display of 1p excitation
% spectrum (for more consistent display)
currData(rowIdx).plotColor = wavelength2RGB(:,find(wavelengthScale>currData(rowIdx).lambdaMaxEm,1))/2;
% currData(rowIdx).plotColor = wavelength2RGB(:,find(wavelengthScale>currData(rowIdx).lambdaMax1pExc,1));
if isempty(currData(rowIdx).plotColor)
currData(rowIdx).plotColor = 0.7*[1 1 1];
end
currData(rowIdx).plotColor(:,2) = wavelength2RGB(:,find(wavelengthScale>currData(rowIdx).lambdaMaxEm,1));
if ~sum(currData(rowIdx).plotColor(:,2))
currData(rowIdx).plotColor(:,2) = 0.7*[1 1 1];
end
if size(currData(rowIdx).data,2) > 4
currData(rowIdx).lambdaMax2pExc = currData(rowIdx).data(find(currData(rowIdx).data(:,6)==max(currData(rowIdx).data(:,6)),1),5);
currData(rowIdx).max2pXSectionVal = max(currData(rowIdx).data(:,6));
currData(rowIdx).plotColor(:,3) = mean([[1 1 1];0.5*currData(rowIdx).plotColor(:,2)'],1);
end
if size(currData(rowIdx).data,2) > 6
currData(rowIdx).lambdaMax3pExc = currData(rowIdx).data(find(currData(rowIdx).data(:,8)==max(currData(rowIdx).data(:,8)),1),7);
currData(rowIdx).max3pXSectionVal = max(currData(rowIdx).data(:,8));
currData(rowIdx).plotColor(:,4) = mean([[1 1 1];[1 1 1];0.5*currData(rowIdx).plotColor(:,2)'],1);
end
end
% Get filter information from edit-boxes
function updateFilterSelection(~,~,idx)
currFilt(idx).wavelength = str2double(get(filtHandles(4,idx),'String'));
currFilt(idx).band = str2double(get(filtHandles(5,idx),'String'));
updateFiltObj;
end
% Load spectral information for light sources or filters
function loadSpectrum(~,~,idx)
[currFilt(idx).spectrumFilename, currFilt(idx).spectrumPathname] = uigetfile([pn filesep 'LightSources+Filter' filesep '*.csv']);
currFilt(idx).spectrum = csvread([currFilt(idx).spectrumPathname currFilt(idx).spectrumFilename]);
set(filtHandles(7,idx), 'String',currFilt(idx).spectrumFilename);
maxPos = find(currFilt(idx).spectrum(:,2) == max(currFilt(idx).spectrum(:,2)),1);
currFilt(idx).wavelength = currFilt(idx).spectrum(maxPos,1);
updateFiltObj;
end
% Update filter/light source settings
function updateFiltObj(varargin)
for ii = 1:numel(currFilt)
if ~isempty(currFilt(ii).handle1D)
delete(currFilt(ii).handle1D);
currFilt(ii).handle1D = [];
end
if ~isempty(currFilt(ii).handle2D)
delete(currFilt(ii).handle2D);
currFilt(ii).handle2D = [];
end
if get(filtHandles(2,ii), 'Value')
yl1D = get(ax1D,'YLim');
yl1D(1) = yl1D(1)+0.1;
yl2D = get(ax2D,'YLim');
xl2D = get(ax2D,'XLim');
if ~isempty(currFilt(ii).wavelength)
filtCol = wavelength2RGB(:,find(wavelengthScale>currFilt(ii).wavelength,1))';
if isempty(filtCol) || currFilt(ii).wavelength<400 || currFilt(ii).wavelength>700
filtCol = 0.8*[1 1 1];
end
switch currFilt(ii).type
case 'excitation'
currFilt(ii).handle1D = fill([currFilt(ii).wavelength-currFilt(ii).band/2 sum(currFilt(ii).wavelength+currFilt(ii).band/2)*[1 1] currFilt(ii).wavelength-currFilt(ii).band/2], [yl1D(1) yl1D(1) yl1D(2) yl1D(2)],filtCol ,'Parent',ax1D, 'Facealpha',0.2, 'EdgeColor','none');
currFilt(ii).handle1D(2) = text(currFilt(ii).wavelength,-0.075,['Exc' num2str(currFilt(ii).wavelength) '/' num2str(currFilt(ii).band)], 'Color',filtCol,'Parent',ax1D, 'HorizontalAlignment','center', 'VerticalAlignment','bottom');
currFilt(ii).handle2D = fill([currFilt(ii).wavelength-currFilt(ii).band/2 sum(currFilt(ii).wavelength+currFilt(ii).band/2)*[1 1] currFilt(ii).wavelength-currFilt(ii).band/2], [yl2D(1) yl2D(1) yl2D(2) yl2D(2)],wavelength2RGB(:,find(wavelengthScale>currFilt(ii).wavelength,1))' ,'Parent',ax2D, 'Facealpha',0.2, 'EdgeColor','none');
% currFilt(ii).handle2D = fill([currFilt(ii).wavelength-currFilt(ii).band/2 sum(currFilt(ii).wavelength+currFilt(ii).band/2)*[1 1] currFilt(ii).wavelength-currFilt(ii).band/2], [,[1 1 1] ,'Parent',ax2D);
case 'emission'
currFilt(ii).handle1D = fill([currFilt(ii).wavelength-currFilt(ii).band/2 sum(currFilt(ii).wavelength+currFilt(ii).band/2)*[1 1] currFilt(ii).wavelength-currFilt(ii).band/2], [yl1D(1) yl1D(1) yl1D(2) yl1D(2)],filtCol,'Parent',ax1D, 'Facealpha',0.2, 'EdgeColor','none');
currFilt(ii).handle1D(2) = text(currFilt(ii).wavelength,-0.075,['Em' num2str(currFilt(ii).wavelength) '/' num2str(currFilt(ii).band)], 'Color',filtCol,'Parent',ax1D, 'HorizontalAlignment','center', 'VerticalAlignment','bottom');
currFilt(ii).handle2D = fill([xl2D(1) xl2D(1) xl2D(2) xl2D(2)], [currFilt(ii).wavelength-currFilt(ii).band/2 sum(currFilt(ii).wavelength+currFilt(ii).band/2)*[1 1] currFilt(ii).wavelength-currFilt(ii).band/2],filtCol,'Parent',ax2D, 'Facealpha',0.2, 'EdgeColor','none');
case 'laser'
currFilt(ii).handle1D = line(currFilt(ii).wavelength*[1 1], yl1D,'Color',filtCol ,'Parent',ax1D, 'LineWidth',1.5);
currFilt(ii).handle2D = line(currFilt(ii).wavelength*[1 1], yl2D,'Color',filtCol ,'Parent',ax2D, 'LineWidth',1.5);
currFilt(ii).handle1D(2) = text(currFilt(ii).wavelength,-0.075,num2str(currFilt(ii).wavelength), 'Color',filtCol,'Parent',ax1D, 'HorizontalAlignment','center', 'VerticalAlignment','bottom');
case 'spectrum'
currFilt(ii).handle1D = plot(currFilt(ii).spectrum(:,1),currFilt(ii).spectrum(:,2)/max(currFilt(ii).spectrum(:,2)), 'Color',filtCol ,'Parent',ax1D, 'LineWidth',1.5);
end
end
end
end
uistack([currFilt(:).handle1D],'bottom');
% uistack([currFilt(:).handle2D],'bottom');
end
% Update plots
function updatePlots(varargin)
cla(ax1D);
cla(ax2D);
plot(ax2D, 1:1600,1:1600,'LineStyle','--','Color',0.5*[1 1 1]);
for ii = 1:numel(currData)
if get(dyeHandles(2,ii), 'Value')
ph = [];
for jj = 1:4
if get(dyeHandles(jj+4,ii), 'Value')
% Plot Normalized values (mostly normalized already, but
% sometimes in range [0,1], sometimes [0,100]
ph(end+1) = plot(ax1D, currData(ii).data(:,jj*2-1),currData(ii).data(:,jj*2)/max(currData(ii).data(:,jj*2)), 'Color',currData(ii).plotColor(:,jj), 'LineWidth', 1.5);
switch jj
case 2
text(ax1D,currData(ii).lambdaMaxEm,1.055+mod(ii-1,4)*0.04,currData(ii).dyeName, 'Color',currData(ii).plotColor(:,jj),'Fontsize',9, 'HorizontalAlignment', 'center', 'VerticalAlignment','bottom', 'Rotation', 0, 'Interpreter','none')
case 3
text(ax1D,currData(ii).lambdaMax2pExc,1.055+mod(ii-1,4)*0.04,[currData(ii).dyeName '-2P' ' (' num2str(currData(ii).max2pXSectionVal, '%6.1f') ' GM)'], 'Color',currData(ii).plotColor(:,jj),'Fontsize',9, 'HorizontalAlignment', 'center', 'VerticalAlignment','bottom', 'Rotation', 0, 'Interpreter','none')
case 4
text(ax1D,currData(ii).lambdaMax3pExc,1.055+mod(ii-1,4)*0.04,[currData(ii).dyeName '-3P' ' (' num2str(currData(ii).max3pXSectionVal, '%6.1f') ')'], 'Color',currData(ii).plotColor(:,jj),'Fontsize',9, 'HorizontalAlignment', 'center', 'VerticalAlignment','bottom', 'Rotation', 0, 'Interpreter','none')
end
% if jj == 3
% ph(end+1) = plot(ax1D, currData(ii).data(plotIdx,jj*2-1)/2,currData(ii).data(plotIdx,jj*2)/max(currData(ii).data(:,jj*2)), 'Color',plotColor, 'LineWidth', 1.5);
% end
end
end
% 2D plot
contHandle = [];
for jj = [1 3 4]
if get(dyeHandles(jj+4,ii), 'Value')
wEx = linspace(min(currData(ii).data(:,jj*2-1)),max(currData(ii).data(:,jj*2-1)),100);
wEm = linspace(min(currData(ii).data(:,3)),max(currData(ii).data(:,3)),100);
% Make sure no wavelength value appears twice and remove NaN values
[c, idx] = unique(currData(ii).data(:,2*jj-1));
notNaN = ~isnan(currData(ii).data(idx,2*jj-1)) & ~isnan(currData(ii).data(idx,2));
interEx = interp1(currData(ii).data(idx(notNaN),2*jj-1),currData(ii).data(idx(notNaN),2*jj),wEx);
[c, idx] = unique(currData(ii).data(:,3));
notNaN = ~isnan(currData(ii).data(idx,3)) & ~isnan(currData(ii).data(idx,4));
interEm = interp1(currData(ii).data(idx(notNaN),3),currData(ii).data(idx(notNaN),4),wEm);
% Calculate and plot combined spectrum
m = repmat(interEx/max(interEx),[100 1]).*repmat(interEm'/max(interEm),[1 100]);
[c, contHandle(end+1)] = contour(ax2D, wEx,wEm,m,[0.99 0.8 0.6 0.4 0.2],'Color',currData(ii).plotColor(:,jj),'LineWidth',1.5);
switch jj
case 1
text(ax2D,currData(ii).lambdaMax1pExc,max(c(2,:))+1 ,currData(ii).dyeName, 'Color',currData(ii).plotColor(:,jj),'Fontsize',9, 'HorizontalAlignment', 'center', 'VerticalAlignment','bottom', 'Rotation', 0, 'Interpreter','none')
case 3
text(ax2D,currData(ii).lambdaMax2pExc,max(c(2,:))+1 ,[currData(ii).dyeName '-2P'], 'Color',currData(ii).plotColor(:,jj),'Fontsize',9, 'HorizontalAlignment', 'center', 'VerticalAlignment','bottom', 'Rotation', 0, 'Interpreter','none')
case 4
text(ax2D,currData(ii).lambdaMax3pExc,max(c(2,:))+1 ,[currData(ii).dyeName '-3P'], 'Color',currData(ii).plotColor(:,jj),'Fontsize',9, 'HorizontalAlignment', 'center', 'VerticalAlignment','bottom', 'Rotation', 0, 'Interpreter','none')
end
end
end
switch mod(ii,4)
case 1
set([ph contHandle], 'LineStyle', ':');
set(dyeHandles(9,ii), 'String', char(183*[1 1 1 1 1]),'FontWeight','bold','ForegroundColor',currData(ii).plotColor(:,2));
case 2
set([ph contHandle], 'LineStyle', '--');
set(dyeHandles(9,ii), 'String', '- - -','FontWeight','bold','ForegroundColor',currData(ii).plotColor(:,2));
case 3
set([ph contHandle], 'LineStyle', '-.');
set(dyeHandles(9,ii), 'String', ['- ' char(183) ' -'],'FontWeight','bold','ForegroundColor',currData(ii).plotColor(:,2));
case 0
set([ph contHandle], 'LineStyle', '-');
set(dyeHandles(9,ii), 'String', '___','FontWeight','bold','ForegroundColor',currData(ii).plotColor(:,2));
end
yl = get(ax2D, 'YLim');
end
end
set([ax1D ax2D], 'XLim',[350 750]);
if nRowsDye == 1
if get(dyeHandles(7,:),'Value')
set([ax1D ax2D], 'XLim',[350 1100]);
end
if get(dyeHandles(8,:),'Value')
set([ax1D ax2D], 'XLim',[350 1500]);
end
else
if sum(cell2mat(get(dyeHandles(7,:),'Value')))
set([ax1D ax2D], 'XLim',[350 1200]);
end
if sum(cell2mat(get(dyeHandles(8,:),'Value')))
set([ax1D ax2D], 'XLim',[350 1500]);
end
end
text(ax2D, mean(get(ax2D, 'XLim')), yl(1)+diff(yl)/20, 'Contour lines at 0.99, 0.8, 0.6, 0.4, 0.2', 'Color', 0.5*[1 1 1], 'HorizontalAlignment','center');
if ~isempty([currFilt(:).handle1D])
updateFiltObj;
end
end
% Close all windows
function closeGui(varargin)
delete([gui fig1D fig2D]);
end
end