function clusterSpots()

global X;

% Get the kind of clustering we will be doing
is_do_manual = getFromTag('is_do_manual');
is_do_brute  = getFromTag('is_do_brute');
is_do_kmeans = getFromTag('is_do_kmeans');

% Check if we remove empty clusters
is_remove_empty = getFromTag('is_no_empty_clusters');

% Grab the Spot Object in the Scene
nS = X.GetNumberOf('Spots');
if nS > 1
    [~, nS] = X.SelectDialog('Spots');
end
spots = X.GetObject('Type', 'Spots', 'Number', nS);

% Grab the channels we will be using
chanIdx = getChannelIndexes();

% Grab the stats we need, namely Intensity Mean
spotsData = X.GetSelectedStatistics(spots, 'Intensity Mean');

% To cluster, we need an nx2 array with
% col1: spotID
% col2: Value of selected statistic
% Get the indices of the chosen statistic

% Build what we need
selectedIds      = spotsData.ids+1;
selectedChannels = cell2mat(spotsData.factors(:,2));
selectedValues   = spotsData.values;


% for all the Ids and all Channels, will fill all values from the chosen statistic
for  i = 1:length(selectedValues)
    fullSpotsDataForCluster(selectedIds(i),str2num(selectedChannels(i))) = selectedValues(i);
end

% Finished data for clustering
spotsClusterData = fullSpotsDataForCluster(:,chanIdx);

% Clear some memory
fullSpotsDataForCluster = [];

%Spot Grouping
spotGrouping = getFromTag('txt_grouping_distance', 'Number');

% Z compensation
zComp = getFromTag('txt_z_compensation_factor', 'Number');

% Grouping Distance for after clustering
minDist = getFromTag('txt_grouping_distance', 'Number');

if is_do_manual
    % Just grab all the channels and all the values and then use the
    % equivalent of the brute-force to get the results
    % How many categories per channel
    nCat = getFromTag('txt_manual_cat_num', 'Number');
    % Make an array of edges for each channel
    edges = zeros(numel(chanIdx), nCat+2); % +2 to include 0 and Infinity
    edges(:,end) = Inf;
    
    % Everything in double loop, first channels
    for c=1:numel(chanIdx)
        %get BG
        edges(c,2) = getFromTag(sprintf('txt_manual_bg_ch_%d',chanIdx(c)), 'Number');
        % Now for each category
        for n=1:(nCat-1)
            edges(c,2+n) = getFromTag(sprintf('txt_manual_cat_%d_ch_%d',n,chanIdx(c)), 'Number');
        end
    end
    
    [edges, clusterIndexes ] = sortManual(spotsClusterData, edges);

    % create a Parent folder with the Cluster Number
    manualFolder = X.CreateGroup(sprintf('Manual Clustering %d categories per channel, Z Compensation [%d]', nCat, zComp ));
    X.AddToScene(manualFolder);
    
    
    clusterDistances(spotsData, clusterIndexes, zComp, minDist, manualFolder);
    disp('Manual Clustering DONE');
    edges
    
end

if is_do_brute
    % Here we use a very simple method to cluster them :
    % Check on each channel for the intensities and categorise them. a
    % binning into N categories for each channel.
    nCat = getFromTag('txt_brute_cat_num', 'Number');
    max = getFromTag('txt_brute_max', 'Number');
    bg = getFromTag('txt_brute_bg', 'Number');

[centroids, clusterIndexes ] = sortBrute(spotsClusterData, nCat, max, bg);
    if (is_remove_empty)
        [centroids, clusterIndexes ] = removeEmptyClusters(centroids, clusterIndexes);
    end
    
    % create a Parent folder with the Cluster Number
    bruteFolder = X.CreateGroup(sprintf('Brute Force Clustering %d categories per channel, Z Compensation [%d]', nCat, zComp ));
    X.AddToScene(bruteFolder);
    
    clusterDistances(spotsData, clusterIndexes, zComp, minDist, bruteFolder);
    disp('Brute Force Clustering DONE');
    centroids
end

if is_do_kmeans
    % Use separate clusterings per channel?
    is_sep_kmeans = getFromTag('is_sep_kmeans');
    
    if is_sep_kmeans
        nClusterPerChannel = getFromTag('txt_kmeans_sep_cluster_num', 'Number');
        opts = statset('Display','final');
        str = '';
        for i=1:numel(chanIdx)
            [clusterIndexes(:,i), centroids(:,i)] = kmeans(spotsClusterData(:,i),nClusterPerChannel,...
                'start','plus',...
                'replicates',50,...
                'emptyaction','drop',...
                'Options',opts);
            
            str = [str '%d'];
        end
        
        [C ia ic] = unique(clusterIndexes, 'rows');
        
        % for the indexes, make a new array from 1 to to numger of unique
        % rows
        newIdx = 1:size(C,1);
        
        % Get the centroids
        cent = [];
        for c=1:numel(chanIdx)
            cent = [cent centroids(C(:,c),c)];
        end
        newIdx = newIdx(ic);

        centroids = cent;

        if (is_remove_empty)
           [centroids, newIdx ] = removeEmptyClusters(centroids, newIdx);
        end
        
        

    
        % create a Parent folder with the Cluster Number
        sepkMeansFolder = X.CreateGroup(sprintf('Separate K-Means With %d Clusters per Channel, Z Compensation [%d]', nClusterPerChannel, zComp ));
        X.AddToScene(sepkMeansFolder);
        clusterDistances(spotsData, newIdx, zComp, minDist, sepkMeansFolder);
        
    else
        
        nClusters = getFromTag('txt_kmeans_cluster_num', 'Number');
        
        opts = statset('Display','final');
        
        [clusterIndexes, centroids] = kmeans(spotsClusterData,nClusters,...
            'start','plus',...
            'replicates',50,...
            'emptyaction','drop',...
            'Options',opts);
        
        % create a Parent folder with the Cluster Number
        kMeansFolder = X.CreateGroup(sprintf('K-Means With %d Clusters, Z Compensation [%d]', nClusters, zComp ));
        X.AddToScene(kMeansFolder);
        if (is_remove_empty)
           [centroids, clusterIndexes ] = removeEmptyClusters(centroids, newIdx);
        end
        
        clusterDistances(spotsData, clusterIndexes, zComp, minDist, kMeansFolder);
        disp('K-Means Clustering DONE');
        
    end
    centroids
end
end