function browse_trajectories(labels_fn, traj, varargin)
%BROWSE_TRAJECTORIES Summary of this function goes here
% no filter at first
global g_config;
addpath(fullfile(fileparts(mfilename('fullpath')), '../extern'));
addpath(fullfile(fileparts(mfilename('fullpath')), '../extern/GUILayout'));
addpath(fullfile(fileparts(mfilename('fullpath')), '../extern/GUILayout/Patch'));
addpath(fullfile(fileparts(mfilename('fullpath')), '../extern/cm_and_cb_utilities'));
filter = 1:traj.count;
sorting = 1:traj.count;
[tags, disp_feat, cluster_feat, selection, ref_set, n_hor, n_ver, name] = process_options(varargin, ...
'Tags', g_config.TAGS, 'Features', g_config.DEFAULT_FEATURE_SET, ...
'ClusteringFeatures', g_config.CLUSTERING_FEATURE_SET, ...
'UserSelection', [], 'ReferenceClassification', [], ...
'ItemsHor', 2, 'ItemsVer', 2, 'Name', 'Trajectories tagging' ...
);
addpath(fullfile(fileparts(mfilename('fullpath')), '../extern'));
% create main window
f = figure('Visible','off', 'name', name, ...
'Position', [200, 200, 1280, 800], 'Menubar', 'none', 'Toolbar', 'none', 'resize', 'on');
% base layout
bg_box = uiextras.VBox('Parent', f);
% combine display + clustering features
feat = [cluster_feat setdiff(disp_feat, cluster_feat)];
%%
%% Create controls
%%%
% control buttons box
views_box = uiextras.VBox('Parent', bg_box);
ctrl_box = uiextras.HBox('Parent', bg_box);
set(bg_box, 'Sizes', [-1 100] );
% box with additional controls on the left
filter_panel = uiextras.BoxPanel('Parent', ctrl_box, 'Title', 'Filter/Sort');
filter_box = uiextras.VBox('Parent', filter_panel);
% box with left navigation controls
lnav_box = uiextras.VBox('Parent', ctrl_box);
% middle status box
stat_box = uiextras.VBox('Parent', ctrl_box);
% box with right navigation controls
rnav_box = uiextras.VBox('Parent', ctrl_box);
% box with additional controls on the right
clus_panel = uiextras.BoxPanel('Parent', ctrl_box, 'Title', 'Clustering');
clus_box = uiextras.VBox('Parent', clus_panel);
% and another one
layout_panel = uiextras.BoxPanel('Parent', ctrl_box, 'Title', 'Layout');
layout_box = uiextras.VBox('Parent', layout_panel);
set(ctrl_box, 'Sizes', [200 75 -1 75 200 350]);
% trajectories navigation
uicontrol('Parent', lnav_box, 'Style', 'pushbutton', 'String', '<-', 'Callback', {@previous_callback});
uicontrol('Parent', rnav_box, 'Style', 'pushbutton', 'String', '->', 'Callback',{@next_callback});
uicontrol('Parent', lnav_box, 'Style', 'pushbutton', 'String', '<<-', 'Callback',{@previous2_callback});
uicontrol('Parent', rnav_box, 'Style', 'pushbutton', 'String', '->>', 'Callback',{@next2_callback});
uicontrol('Parent', lnav_box, 'Style', 'pushbutton', 'String', '<<<-', 'Callback',{@previous3_callback});
uicontrol('Parent', rnav_box, 'Style', 'pushbutton', 'String', '->>>', 'Callback',{@next3_callback});
% status text (middle)
status_handle = uicontrol('Parent', stat_box, 'Style', 'text', 'String', '');
% clustering controls
uicontrol('Parent', clus_box, 'Style', 'text', 'String', '# of clusters:');
vals = arrayfun( @(x) sprintf('%d', x), 1:500, 'UniformOutput', 0);
hclusters = uicontrol('Parent', clus_box, 'Style', 'popupmenu', 'String', vals);
hbox = uiextras.HBox('Parent', clus_box);
hcv = uicontrol('Parent', hbox, 'Style', 'checkbox', 'String', 'Enable CV');
hshow_results = uicontrol('Parent', hbox, 'Style', 'checkbox', 'String', 'Pop-out Res.', 'Callback', {@popout_results_callback});
uicontrol('Parent', clus_box, 'Style', 'pushbutton', 'String', 'Cluster', 'Callback', {@cluster_callback});
% feature sorting control
hfilter = [];
sortstr = {'** none **', '** distance to centre (max) **', '** distance to centre (euclidean) **', '** combined **', '** random **' };
for i = 1:length(feat) % have to do this way because of stupid matlab
tmp = g_config.FEATURES{feat(i)};
sortstr = [sortstr, tmp{2}];
end
sort_box = uiextras.HBox('Parent', filter_box);
uicontrol('Parent', sort_box, 'Style', 'text', 'String', 'Sort:');
hsort = uicontrol('Parent', sort_box, 'Style', 'popupmenu', 'String', sortstr, 'Callback', {@sorting_callback});
hsort_reverse = uicontrol('Parent', filter_box, 'Style', 'checkbox', 'String', 'Reverse', 'Callback', {@sorting_callback});
set(sort_box, 'Sizes', [40, -1]);
% cluster navigation and control (note: combo-box is created elsewhere
% since it is dynamic
filter_combo_box = uiextras.HBox('Parent', filter_box);
filter_nav_box = uiextras.HButtonBox('Parent', filter_box);
hfilter_prev = uicontrol('Parent', filter_nav_box, 'Style', 'pushbutton', 'String', '<-', 'Callback', {@filter_prev_callback});
hfilter_next = uicontrol('Parent', filter_nav_box, 'Style', 'pushbutton', 'String', '->', 'Callback', {@filter_next_callback});
nitems_filter = 0;
% layout controls
box = uiextras.HBox('Parent', layout_box);
uicontrol('Parent', box, 'Style', 'text', 'String', 'NX:');
xviews_handle = uicontrol('Parent', box, 'Style', 'popupmenu', 'String', {'1', '2', '3', '4', '5', '6'}, 'Callback', {@layout_change_callback});
set(xviews_handle, 'value', n_ver);
uicontrol('Parent', box, 'Style', 'text', 'String', 'NY:');
yviews_handle = uicontrol('Parent', box, 'Style', 'popupmenu', 'String', {'1', '2', '3', '4', '5', '6'}, 'Callback', {@layout_change_callback});
set(yviews_handle, 'value', n_hor);
uicontrol('Parent', box, 'Style', 'text', 'String', 'Tol:');
tol_str = arrayfun( @(x) num2str(x), 1:25, 'UniformOutput', 0);
simplify_tol_handle = uicontrol('Parent', box, 'Style', 'popupmenu', 'String', tol_str, 'Callback', {@layout_change_callback});
set(simplify_tol_handle, 'value', 5);
% build a list with all the possible data representations
strs = {};
for i = 1:length(g_config.DATA_REPRESENTATION)
tmp = g_config.DATA_REPRESENTATION{i};
strs = [strs, tmp{1}];
end
if ~isempty(traj.parent)
full_status = 'on';
else
full_status = 'off';
end
strs = ['None', strs];
% 1st combo: main view
box = uiextras.HBox('Parent', layout_box);
uicontrol('Parent', box, 'Style', 'text', 'String', 'Main:');
main_view_combo = uicontrol('Parent', box, 'Style', 'popupmenu', 'String', strs, 'Callback', {@layout_change_callback}, 'Value', 2);
main_view_dir_check = uicontrol('Parent', box, 'Style', 'checkbox', 'String', 'Vec.', 'Callback', {@layout_change_callback});
main_view_full_combo = uicontrol('Parent', box, 'Style', 'popupmenu', 'String', strs, 'Callback', {@layout_change_callback}, 'Enable', full_status);
set(box, 'Sizes', [50, -1, 50, -1]);
% 2nd combo: secondary view 1
box = uiextras.HBox('Parent', layout_box);
uicontrol('Parent', box, 'Style', 'text', 'String', 'Sec. 1:');
sec_view_combos = [uicontrol('Parent', box, 'Style', 'popupmenu', 'String', strs, 'Callback', {@layout_change_callback})];
sec_view_dir_check = uicontrol('Parent', box, 'Style', 'checkbox', 'String', 'Vec.', 'Callback', {@layout_change_callback});
sec_view_full_combos = [uicontrol('Parent', box, 'Style', 'popupmenu', 'String', strs, 'Callback', {@layout_change_callback}, 'Enable', full_status)];
set(box, 'Sizes', [50, -1, 50, -1]);
% 3rd combo: secondary view 2
box = uiextras.HBox('Parent', layout_box);
uicontrol('Parent', box, 'Style', 'text', 'String', 'Sec. 2:');
sec_view_combos = [ sec_view_combos, ...
uicontrol('Parent', box, 'Style', 'popupmenu', 'String', strs, 'Callback', {@layout_change_callback}) ...
];
sec_view_dir_check = [sec_view_dir_check, uicontrol('Parent', box, 'Style', 'checkbox', 'String', 'Vec.', 'Callback', {@layout_change_callback})];
sec_view_full_combos = [sec_view_full_combos, uicontrol('Parent', box, 'Style', 'popupmenu', 'String', strs, 'Callback', {@layout_change_callback}, 'Enable', full_status)];
set(box, 'Sizes', [50, -1, 50, -1]);
sec_view_handles = [];
views_grid = [];
views_panels = [];
axis_handles = [];initialize
desc_handles = [];
view_panels = [];
cb_handles = [];
simplify_level_prev = 0;
ntags = length(tags);
% normalization values for speed and other scalar values
data_repr_norm = zeros(1, length(g_config.DATA_REPRESENTATION));
data_repr_off = zeros(1, length(g_config.DATA_REPRESENTATION));
create_views();
cur = 1; %current index
% read labels if we already have something
labels_traj = zeros(traj.count, length(tags));
if exist(labels_fn, 'file')
[labels_data, label_tags] = traj.read_tags(labels_fn, g_config.TAG_TYPE_ALL);
[labels_map, labels_idx] = traj.match_tags(labels_data, label_tags);
non_matched = sum(labels_idx == -1);
if non_matched > 0
fprintf('Warning: %d unmatched trajectories/segments found!\n', non_matched);
end
% match tags with complete list of tags
for i = 1:length(label_tags)
for j = 1:length(tags)
if strcmp(label_tags(i).abbreviation, tags(j).abbreviation)
labels_traj(:, j) = labels_map(:, i);
break;
end
end
end
end
classif_res = [];
distr_status = '';
covering = [];
feat_values = traj.compute_features(feat);
segments_map = [];
diff_set = [];
update_filter_combo;
show_trajectories;
results_window = [];
set(f, 'Visible', 'on');
%%
%% nested functions
%%
function [nx, ny] = number_of_views()
nx = get(xviews_handle, 'value');
ny = get(yviews_handle, 'value');
end
function create_views()
% create base grid
if ~isempty(views_grid)
delete(views_grid);
end
views_grid = uiextras.Grid('Parent', views_box);
views_panels = [];
axis_handles = [];
view_panels = [];
desc_handles = [];
cb_handles = [];
sec_view_handles = [];
[nx, ny] = number_of_views();
main1 = get(main_view_combo, 'value');
main2 = get(main_view_full_combo, 'value');
main = (main1 > 1 || main2 > 1);
sec1 = get(sec_view_combos(1), 'value');
sec1main = get(sec_view_full_combos(1), 'value');
sec2 = get(sec_view_combos(2), 'value');
sec2main = get(sec_view_full_combos(2), 'value');
sec = (sec1 > 1 || sec2 > 1 || sec1main > 1 || sec2main > 1);
for j =1:nx
for i = 1:ny
view_panels = [view_panels, uiextras.BoxPanel('Parent', views_grid)];
% boxes for the view (a vertical one for the checkboxes)
view_hbox = uiextras.HBox('Parent', view_panels(end));
% trajectory display
view_vbox = uiextras.VBox('Parent', view_hbox);
% do we have any secondary views ?
if (sec)
hbox = uiextras.HBox('Parent', view_vbox);
if main
axis_handles = [axis_handles, axes('Parent', hbox)];
else
uicontrol('Parent', hbox, 'Style', 'text', 'String', 'None');
end
% create another box for the secondary views
vbox = uiextras.VBox('Parent', hbox);
if (sec1 > 1)
sec_view_handles = [sec_view_handles , axes('Parent', vbox)];
else
sec_view_handles = [sec_view_handles, uicontrol('Parent', vbox, 'Style', 'text', 'String', 'None')];
end
if (sec2 > 1)
sec_view_handles = [sec_view_handles, axes('Parent', vbox)];
else
sec_view_handles = [sec_view_handles, uicontrol('Parent', vbox, 'Style', 'text', 'String', 'None')];
end
else
if main
axis_handles = [axis_handles, axes('Parent', view_vbox)];
else
uicontrol('Parent', view_vbox, 'Style', 'text', 'String', 'None');
end
end
% trajectory description
desc_handles = [desc_handles, uicontrol('Parent', view_vbox, 'Style', 'text')];
set(view_vbox, 'Sizes', [-1, 35]);
% check boxes with tags
% yet another box
cb_box = uiextras.VButtonBox('Parent', view_hbox);
set(view_hbox, 'Sizes', [-1, 50]);
hcb_new = [];
for k = 1:ntags
txt = tags(k).abbreviation;
hcb_new = [ hcb_new, ...
uicontrol('Parent', cb_box, 'Style', 'checkbox', 'String', txt, 'Callback', {@checkbox_callback}) ...
];
end
cb_handles = [cb_handles; hcb_new];
end
end
set(views_grid, 'RowSizes', -1*ones(1, ny), 'ColumnSizes', -1*ones(1, nx));
end
function update_filter_combo
if ~isempty(hfilter)
delete(hfilter);
hfilter = [];
end
strings = {'** all **', '** tagged **', '** untagged **', '** isolated **', '** suspicious **', '** selection **', '** compare **', '** errors **'};
if ~isempty(classif_res)
strings = [strings, arrayfun( @(t) t.description, classif_res.classes, 'UniformOutput', 0)];
end
if ~isempty(classif_res)
% isolated/lonely segments
isol = ~covering;
for i = 1:max(classif_res.nclusters)
if classif_res.cluster_class_map(i) == 0
lbl = g_config.UNDEFINED_TAG_ABBREVIATION;
else
lbl = classif_res.classes(classif_res.cluster_class_map(i)).abbreviation;
end
nclus = sum(classif_res.cluster_index == i);
strings = [strings, sprintf('Cluster #%d (''%s'', N=%d, L=%d, I=%d)', ...
i, lbl, nclus, ...
length(find(sum(labels_traj(classif_res.cluster_index == i, :), 2) > 0)), ...
sum(isol(classif_res.cluster_index == i)))];
end
end
hfilter = uicontrol('Parent', filter_combo_box, 'Style', 'popupmenu', 'String', strings, 'Callback', {@combobox_filter_callback});
nitems_filter = length(strings);
combobox_filter_callback(0, 0);
end
function plot_trajectory(tr, repr, vec, tol, hl)
lw = 1.2;
lc = [0 0 0];
if hl
hold on;
lw = 2;
lc = [0 1 0];
else
axis off;
daspect([1 1 1]);
rectangle('Position',[g_config.CENTRE_X - g_config.ARENA_R, g_config.CENTRE_X - g_config.ARENA_R, g_config.ARENA_R*2, g_config.ARENA_R*2],...
'Curvature',[1,1], 'FaceColor',[1, 1, 1], 'edgecolor', [0.2, 0.2, 0.2], 'LineWidth', 3);
hold on;
axis square;
% see if we have a platform to draw
if isprop(g_config, 'PLATFORM_X')
rectangle('Position',[g_config.PLATFORM_X - g_config.PLATFORM_R, g_config.PLATFORM_Y - g_config.PLATFORM_R, 2*g_config.PLATFORM_R, 2*g_config.PLATFORM_R],...
'Curvature',[1,1], 'FaceColor',[1, 1, 1], 'edgecolor', [0.2, 0.2, 0.2], 'LineWidth', 3);
end
end
dr_param = g_config.DATA_REPRESENTATION{repr};
dt = dr_param{2};
pts = tr.data_representation(repr, 'SimplificationTolerance', tol);
% if the tolerance changed re-scale everything
if tol ~= simplify_level_prev
data_repr_norm = zeros(1, length(data_repr_norm));
simplify_level_prev = tol;
end
if dt == base_config.DATA_TYPE_COORDINATES
if vec
% simplify trajectory
sz = getpixelposition(gca);
for ii = 2:size(pts, 1)
arrow(pts(ii - 1, 2:3), pts(ii, 2:3), 'LineWidth', lw, 'Length', min(sz(3), sz(4))*0.04, 'FaceColor', lc, 'EdgeColor', lc);
end
else
plot(pts(:,2), pts(:,3), '-', 'LineWidth', lw, 'Color', lc);
end
elseif dt == base_config.DATA_TYPE_SCALAR_FIELD
% normalize values
if data_repr_norm(repr) == 0
val_min = [];
val_max = [];
for ii = 1:length(traj.items)
tmp = traj.items(ii).data_representation(repr, 'SimplificationTolerance', tol);
if isempty(val_min)
val_min = min(tmp(:, 4));
val_max = max(tmp(:, 4));
else
val_min = min(val_min, min(tmp(:, 4)));
val_max = max(val_max, max(tmp(:, 4)));
end
end
data_repr_norm(repr) = 1/(val_max - val_min);
data_repr_off(repr) = val_min;
end
pts(:, 4) = (pts(:, 4) - data_repr_off(repr))*data_repr_norm(repr);
cm = jet;
n = 20;
cm = cmapping(n + 1, cm);
fac = 1/n;
np = size(pts, 1);
if vec
clr = cm(floor(pts(:, 4) ./ repmat(fac, np, 1)) + 1, :);
sz = getpixelposition(gca);
for ii = 2:size(pts, 1)
arrow(pts(ii - 1, 2:3), pts(ii, 2:3), 'FaceColor', clr(ii, :), 'EdgeColor', clr(ii, :), 'LineWidth', lw, 'Length', min(sz(3), sz(4))*0.04);
end
else
clr = floor(pts(:, 4) ./ repmat(fac, np, 1) + 1);
z = zeros(1,np);
surface( [pts(:,2)'; pts(:,2)'], [pts(:,3)'; pts(:,3)'], [z;z], [clr'; clr'], ...
'facecol','no', 'edgecol', 'interp', 'linew', 2);
colormap(cm);
end
elseif dt == base_config.DATA_TYPE_EVENTS
% plot coordinates
plot(pts(:,2), pts(:,3), '-', 'LineWidth', lw, 'Color', [0 0 0]);
% and plot points for the events
pos = find(pts(:,4) > 0);
sz = getpixelposition(gca);
r = sz(3)*0.005;
for kk = 1:length(pos)
rectangle('Position', [pts(pos(kk), 2) - r, pts(pos(kk), 3) - r, 2*r, 2*r], 'Curvature', [1,1], 'FaceColor', [1 0 0]);
end
end
set(gca, 'LooseInset', [0,0,0,0]);
end
function show_trajectories
[nx, ny] = number_of_views();
for i = 1:nx*ny
if cur + i < length(filter)
traj_idx = filter(sorting(cur + i - 1));
% plot views
for k = 1:3
if k == 1
idx = get(main_view_combo, 'value') - 1;
idxfull = get(main_view_full_combo, 'value') - 1;
if idx == 0 && idxfull == 0
continue;
end
vec = get(main_view_dir_check, 'value');
set(f, 'currentaxes', axis_handles(i));
else
if isempty(sec_view_handles)
break;
end
idx = get(sec_view_combos(k - 1), 'value') - 1; % second -1 because of the "none"
idxfull = get(sec_view_full_combos(k - 1), 'value') - 1; % second -1 because of the "none"
vec = get(sec_view_dir_check(k - 1), 'value');
if idx == 0 && idxfull == 0
continue; % "none"
end
set(f, 'currentaxes', sec_view_handles((i - 1)*2 + k - 1));
end
hasfull = idxfull > 0 && idxfull <= length(g_config.DATA_REPRESENTATION);
if hasfull
% look for parent trajectory
id = traj.items(traj_idx).identification;
for l = 1:traj.parent.count
id2 = traj.parent.items(l).identification;
len = length(id) - 1;
if isequal(id(1:len), id2(1:len))
plot_trajectory(traj.parent.items(l), idxfull, 0, 0, 0);
break;
end
end
end
if idx > 0 && idx <= length(g_config.DATA_REPRESENTATION)
if vec
tol = get(simplify_tol_handle, 'value')*0.01*g_config.ARENA_R;
else
tol = 0;
end
plot_trajectory(traj.items(traj_idx), idx, vec, tol, hasfull);
end
end
hold on;
if ~isempty(covering)
if covering(traj_idx)
rectangle('Position', [80, 80, 10, 10], 'FaceColor', [0.5, 1, 0.5]);
else
rectangle('Position', [80, 80, 10, 10], 'FaceColor', [1, 0.5, 0.5]);
end
end
% update the status text with feature values
str = '';
for j = 1:length(feat)
if j > 1
str = strcat(str, ' | ');
end
tmp = g_config.FEATURES{feat(j)};
str = strcat(str, sprintf('%s: %.4f', tmp{1}, feat_values(traj_idx, j)));
end
set(desc_handles(i), 'String', str);
% put segment identification in the title
str = sprintf('id: %d | set: %d | track: %d | session: %d | trial:%d +%dcm', traj.items(traj_idx).id, traj.items(traj_idx).set, traj.items(traj_idx).track, traj.items(traj_idx).session, traj.items(traj_idx).trial, round(traj.items(traj_idx).offset));
if ~isempty(classif_res)
str = sprintf('%s || cluster #%d', str, classif_res.cluster_index(traj_idx));
end
set(view_panels(i), 'Title', str);
% update checkboxes
handles = cb_handles(i, :);
arrayfun(@(h,j) set(h, 'Value', labels_traj(traj_idx, j)), handles(1:(length(handles) - 1)), 1:(length(handles) - 1));
for j = 1:(length(handles) - 1)
% by default no color
c = get(gcf,'DefaultUicontrolBackgroundCol');
if ~isempty(classif_res)
idx = -1;
if strcmp(tags(j).abbreviation, g_config.UNDEFINED_TAG_ABBREVIATION)
idx = 0;
else
for k = 1:length(classif_res.classes)
if strcmp(tags(j).abbreviation, classif_res.classes(k).abbreviation)
idx = k;
break;
end
end
end
% see if we have a segment for comparison
if ~isempty(ref_set) && diff_set(traj_idx) == idx
c = [0.6 0.0 0.0];
end
if idx ~= -1 && classif_res.class_map(traj_idx) == idx
if labels_traj(traj_idx, j)
c = [0.2, 1., 0.2];
else
if ~isempty(find(labels_traj(traj_idx, :)))
c = [1., 0.2, 0.2];
else
c = [.5, 0.5, 0.9];
end
end
end
end
set(handles(j), 'BackgroundCol', c);
end
% "unknown" is treated separatedly
if ~isempty(classif_res) && (classif_res.class_map(traj_idx) == -1)
set(handles(end), 'BackgroundCol', [1., 1., 0.3]);
else
set(handles(end), 'BackgroundCol', get(gcf,'DefaultUicontrolBackgroundCol'));
end
end
end
update_status;
end
function save_data
% save values from screen
[nx, ny] = number_of_views;
for i = 0:nx*ny - 1
if length(filter) >= cur + i
vals = arrayfun(@(h) get(h, 'Value'), cb_handles(i + 1, :));
labels_traj(filter(sorting(cur + i)), :) = vals;
end
end
traj.save_tags(labels_fn, tags, labels_traj, []);
end
function update_status
[nx, ny] = number_of_views;
str = sprintf('%d to %d from %d\n\n', cur, cur + nx*ny - 1, length(filter));
first = 1;
for i = 1:length(tags)
n = sum(labels_traj(filter, i));
if n > 0
if first
first = 0;
str = strcat(str, sprintf('\n%s: %d ', tags(i).abbreviation, n));
else
str = strcat(str, sprintf(' | %s: %d', tags(i).abbreviation, n));
end
end
end
if ~isempty(classif_res)
pcov = sum(covering) / traj.count;
str = strcat(str, sprintf('\nErrors: %d (%.3f%%) | Unknown: %.1f%% | Coverage: %.1f%%', ...
classif_res.nerrors, classif_res.perrors*100, classif_res.punknown*100, pcov*100));
end
if ~isempty(diff_set)
str = strcat(str, sprintf(' | Agreement: %.1f%%', 100.* ...
sum(diff_set == 0) / sum(diff_set > -1) ...
));
end
str = sprintf('%s\n%s', str, distr_status);
set(status_handle, 'String', str);
end
function checkbox_callback(source, eventdata)
save_data;
update_status;
end
function combobox_filter_callback(source, eventdata)
val = get(hfilter, 'value');
switch val
case 1
% everyone
filter = 1:traj.count;
case 2
% everyone labelled filter = find(sum(labels_traj, 2) > 0);
filter = find(sum(labels_traj, 2) > 0);
case 3
% everyone not labelled
filter = find(sum(labels_traj, 2) == 0);
case 4
filter = find(covering == 0);
case 5
% "suspicious" guys
if ~isempty(classif_res)
if isempty(segments_map)
[~, ~, segments_map] = classif_res.mapping_ordered(-1, 'MinSegments', 4);
end
filter = find(segments_map ~= classif_res.class_map & segments_map > 0 & classif_res.class_map > 0);
end
case 6
% user selection
filter = selection;
case 7
% reference classification
if ~isempty(diff_set)
filter = find(diff_set > 0);
end
case 7
% mis-matched classifications
if ~isempty(classif_res)
filter = classif_res.non_empty_labels_idx(classif_res.errors == 1);
else
filter = 1:traj.count;
end
otherwise
% classes
if val <= classif_res.nclasses + 8
if classif_res.classes(val - 8).abbreviation == g_config.UNDEFINED_TAG_ABBREVIATION
filter = find(classif_res.class_map == 0);
else
filter = find(classif_res.class_map == (val - 8));
end
else
% clusters
filter = find(classif_res.cluster_index == (val - classif_res.nclasses - 8));
end
end
% status text string
if ~isempty(classif_res)
vals = unique(classif_res.class_map(filter));
pc = arrayfun( @(v) sum(classif_res.class_map(filter) == v)*100. / length(filter), vals);
[pc, idx] = sort(pc, 'descend');
vals = vals(idx);
distr_status = '';
for i = 1:length(vals)
if vals(i) == 0
lbl = g_config.UNDEFINED_TAG_ABBREVIATION;
else
lbl = classif_res.classes(vals(i)).abbreviation;
end
if i == 1
distr_status = strcat(distr_status, sprintf('%s: %.1f%% ', lbl, pc(i)));
else
distr_status = strcat(distr_status, sprintf(' | %s: %.1f%% ', lbl, pc(i)));
end
end
end
update_sorting;
cur = 1;
show_trajectories;
update_filter_navigation();
end
function update_sorting
val = get(hsort, 'value');
rev = get(hsort_reverse, 'value');
switch val
case 1
sorting = 1:length(filter);
case 2
% distance to centre of clusters
middle = (min(feat_values(filter, :)) + max(feat_values(filter, :))) / 2;
nz = all(feat_values(filter, :) ~= 0);
vals = (feat_values(filter, nz) - repmat( middle(nz), length(filter), 1)) ./ repmat( max(feat_values(filter, nz)) - min(feat_values(filter, nz)), length(filter), 1);
dist = max(abs(vals), [], 2);
% dist = (norm_feat_values(filter, :) - classif_res.centroids(:, classif_res.cluster_idx(filter), :)').^2;
[~, sorting] = sort(dist);
case 3
% distance to centre of clusters
feat_norm = max(feat_values) - min(feat_values);
dist = ((feat_values(filter, :) - classif_res.centroids(:, classif_res.cluster_index(filter), :)') / repmat(feat_norm, size(feat_values, 1), 1)).^2;
[~, sorting] = sort(dist);
case 4
% distance function
dist = sum((feat_values(filter, :) ./ repmat( max(feat_values(filter, :)) - min(feat_values(filter, :)), length(filter), 1)).^2, 2);
[~, sorting] = sort(dist);
case 5
% random
sorting = randperm(length(filter));
otherwise
% sort by a single feature
featval = feat_values;
featval = featval(filter, :);
[~, sorting] = sort(featval(:, val - 5));
end
if rev
sorting = sorting(end:-1:1);
end
end
function update_filter_navigation()
if get(hfilter, 'value') == nitems_filter
set(hfilter_next, 'Enable', 'off');
else
set(hfilter_next, 'Enable', 'on');
end
if get(hfilter, 'value') == 1
set(hfilter_prev, 'Enable', 'off');
else
set(hfilter_prev, 'Enable', 'on');
end
end
function filter_next_callback(source, eventdata)
val = get(hfilter, 'value');
set(hfilter, 'value', val + 1);
combobox_filter_callback(0, 0);
end
function filter_prev_callback(source, eventdata)
val = get(hfilter, 'value');
set(hfilter, 'value', val - 1);
combobox_filter_callback(0, 0);
end
function layout_change_callback(source, eventdata)
create_views;
show_trajectories;
end
function sorting_callback(source, eventdata)
update_sorting;
cur = 1;
show_trajectories;
end
function previous_callback(source, eventdata)
[nx, ny] = number_of_views();
if cur >= nx*ny + 1
cur = cur - nx*ny;
show_trajectories;
end
end
function next_callback(source, eventdata)
[nx, ny] = number_of_views();
cur = cur + nx*ny;
if cur > (length(filter) - nx*ny + 1)
cur = length(filter) - nx*ny + 1;
end
show_trajectories;
end
function previous2_callback(source, eventdata)
cur = cur - floor(0.01*length(filter));
if cur < 1
cur = 1;
end
show_trajectories;
end
function next2_callback(source, eventdata)
cur = cur + floor(0.01*length(filter));
if cur > (length(filter) - 3)
cur = length(filter) - 3;
end
show_trajectories;
end
function previous3_callback(source, eventdata)
cur = cur - floor(0.05*length(filter));
if cur < 1
cur = 1;
end
show_trajectories;
end
function next3_callback(source, eventdata)
cur = cur + floor(0.05*length(filter));
if cur > (length(filter) - 3)
cur = length(filter) - 3;
end
show_trajectories;
end
function cluster_callback(source, eventdata)
set(gcf,'Pointer','watch');
nclusters = get(hclusters, 'value');
cv = get(hcv, 'value');
if cv
test_p = 0.1;
else
test_p = 0.;
end
classif = traj.classifier(labels_fn, cluster_feat, g_config.TAG_TYPE_BEHAVIOUR_CLASS);
classif_res = classif.cluster(nclusters, test_p);
if ~isempty(ref_set)
diff_set = classif_res.difference(ref_set);
end
segments_map = [];
[~, covering] = classif_res.coverage();
update_filter_combo;
set(gcf,'Pointer','arrow');
if ~isempty(results_window) && ishandle(results_window.window)
results_window.set_results(classif_res);
end
end
function popout_results_callback(source, eventdata)
if get(hshow_results, 'value') && ( isempty(results_window) || ~ishandle(results_window.window) )
results_window = classification_results(traj);
if ~isempty(classif_res)
results_window.set_results(classif_res);
end
end
if ~isempty(results_window) && ishandle(results_window.window)
results_window.show(get(hshow_results, 'value'));
end
end
end