Skip to content

Commit b55394f

Browse files
pollaroAndyactions-user
authored
[NET-117] Network Test Refactor (#11)
* Starting repository for quick-fix network test refactor over since I screwed up the commit history of the last one. * Added new tests for Network Tests * Added result class for new network tests and fixed some of the test classes * add unit tests for new test classes * reorganize methods in TestPool for readability * lots of edits to NetworkTestResult for methods. I don't think its going to work and need a night to think on it * remove a class i made to test a few things * fixed NetworkTestResult to account for different test methods * did a better job with NetworkTestResult and tests. now its ready to interface with testpool and resultrank * start fixing up testpool and result rank. * added unit tests for NetworkTestResult * this seems way too easy. * copied lots of files needed for permutations and test/result running. Will modify later. Tests run all the way through. * lots of work on network test results and the result app front to get them to interact nicely. some work on resultpool, too * first draft of new class for plotting results parameters. * first batch of plotting tools made. not very pleased, but what can you do * bug squash to get no permutations to display figures * got most of the interfaces and even some of the plotting done. switching to 125 * trying to fix input problems with similar names * Revert "trying to fix input problems with similar names" This reverts commit 291327d. * had to fix bringing in input options due to them being used for plotting and not just testing. grrrr * Add cohens d test * within net pair plotting * fix some code to be more concise * fix some code to be more concise * changed display name for results * added chord plotter and trying to integrate it into no permutations * fixing some chord plotting and adding in trimatrix * fixes for all chords * added comments and some rearrange * added edge tests back that were lost * rewrite network tests tests * Added some unit tests and fixed a few errors * moved a lot of the plotting to seperate functions * Moved plotting into separate functions for hopefully more readability * just a few cleanups * added a test for result rank * added convergence plotting functions/methods * rename some variables * formatting and comments * Added MatrixPlot in * fixed plotting bugs * bug fixes * cleaned up some code and bug fixes * remove outdated tests * Tried to clean up and organize better. Still messy * Added error check to ensure both limit values are input and not none or one * network level chords working * remove two unneeded files * Attempting to get edge chord plotting working * chordplot used in all chord plotting instead of old function * Comments and documentation of chordplot * just some comment refining * integrate chordplot class into net refactor * touch up on formatting * Create development branch. Add initial error logging function * added caption to colorbar for trimatrix plots * added caption to colorbar for trimatrix plots * fixed export yml and python app * trying to fix yml * fixed export and action commit added export files remove matlab folder * [NET-148] Statistical Rank of refactored Network Test Results (#7) * Fix bug in merge function of PermBase when taking single result. Now takes either single result or cell array * NET53 ChordPlot Class (#5) * network level chords working * remove two unneeded files * Attempting to get edge chord plotting working * chordplot used in all chord plotting instead of old function * Comments and documentation of chordplot * just some comment refining * remove commented lines * Create export-mlapp-files.yml * NET-149 Save figures as svg (#6) * add svg option to save figure * remove useless file * remove comment marks * added code to rank by stat. need to fix fron * fixed export yml and python app fixed export yml and python app trying to fix yml * fixed many many conflicts between old network system and new remove unneeded sort * fix merge and squash conflicts * still trying to get this export to work * trying to fix export issues * Add Changes * Update export-mlapp-files.yml * Exported mlapp files * removed old network test folder --------- Co-authored-by: Andy <me@something.com> Co-authored-by: Github Action <action@github.com> * split resultrank to functions and rewrite tests * added script for tests runner. may not need * Update export-mlapp-files.yml added exit 0 on commit to hopefully stop error * trying to create test runner to make up for mathworks rigid workflows and cludges * Create run_matlab_tests.yml * Update run_matlab_tests.yml * fixing some tests * Update run_matlab_tests.yml * change script to function * Update run_matlab_tests.yml * trying to find magnitude error * Update run_matlab_tests.yml * add rounding in for results as largest offage was 10^-13 * coverage report works. damn. * Exported mlapp files * fixed up testpool to work with new networktestresult * remove accidentally save file * fixed NLAResult * remove coverage report from tests local * Exported mlapp files * fixes for testpool and nlaresult * fixed set up of permutation test in unittest * Exported mlapp files * remove unused binary search * fix deleted file * remove ranking test script --------- Co-authored-by: Andy <me@something.com> Co-authored-by: Github Action <action@github.com>
1 parent d368b9f commit b55394f

79 files changed

Lines changed: 2632 additions & 1832 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

+nla/+edge/+result/Base.m

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,10 @@ function output(obj, net_atlas, flags, prob_label)
4040
matrix_plot.displayImage();
4141
w = matrix_plot.image_dimensions("image_width");
4242
h = matrix_plot.image_dimensions("image_height");
43-
%
43+
44+
if ~isfield(flags, 'display_sig')
45+
flags.display_sig = true;
46+
end
4447
if flags.display_sig
4548
if ~exist('prob_label', 'var')
4649
prob_label = [sprintf('Edge-level Significance (P < %g)', obj.prob_max), prob_label_appended];
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
classdef EdgeTestsTest < matlab.unittest.TestCase
2+
3+
properties
4+
variables
5+
end
6+
7+
methods (TestClassSetup)
8+
function loadTestData(testCase)
9+
testCase.variables = load("edgeTestInputStruct.mat");
10+
end
11+
end
12+
13+
methods (TestClassTeardown)
14+
function clearTestData(testCase)
15+
clear
16+
end
17+
end
18+
19+
methods (Test)
20+
function kendallBTest(testCase)
21+
import nla.edge.test.KendallB
22+
% Your guess is as good as mine on why I need the full path
23+
% here and not above
24+
load(fullfile("+nla", "+edge", "unittests", "edgeKendallBResult.mat"), "result");
25+
kendallB = KendallB();
26+
expected = kendallB.run(testCase.variables.input_struct);
27+
testCase.verifyEqual(round(result.coeff.v, 6), round(expected.coeff.v, 6));
28+
end
29+
30+
function pearsonTest(testCase)
31+
import nla.edge.test.Pearson
32+
load(fullfile("+nla", "+edge", "unittests", "edgePearsonResult.mat"), "result");
33+
pearson = Pearson();
34+
expected = pearson.run(testCase.variables.input_struct);
35+
testCase.verifyEqual(round(result.coeff.v, 6), round(expected.coeff.v, 6));
36+
end
37+
38+
function spearmanTest(testCase)
39+
import nla.edge.test.Spearman
40+
load(fullfile("+nla", "+edge", "unittests", "edgeSpearmanResult.mat"), "result");
41+
spearman = Spearman();
42+
expected = spearman.run(testCase.variables.input_struct);
43+
testCase.verifyEqual(round(result.coeff.v, 6), round(expected.coeff.v, 6));
44+
end
45+
46+
function spearmanEstimatorTest(testCase)
47+
import nla.edge.test.SpearmanEstimator
48+
load(fullfile("+nla", "+edge", "unittests", "edgeSpearmanEstimatorResult.mat"), "result");
49+
spearman_estimator = SpearmanEstimator();
50+
expected = spearman_estimator.run(testCase.variables.input_struct);
51+
testCase.verifyEqual(round(result.coeff.v, 6), round(expected.coeff.v, 6));
52+
end
53+
end
54+
end
405 KB
Binary file not shown.
802 KB
Binary file not shown.
736 KB
Binary file not shown.
736 KB
Binary file not shown.
49.9 MB
Binary file not shown.

+nla/+gfx/+plots/MatrixPlot.m

Lines changed: 97 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
axes % The axes of the plot
3131
image_display % The actual displayed values
3232
color_bar % The colorbar
33+
colorbar_contextmenu % The right click menu for the colorbar
3334
end
3435

3536
properties (Dependent)
@@ -289,9 +290,19 @@ function addCallback(obj, x)
289290
end
290291
end
291292

292-
function obj = embiggenMatrix(obj)
293+
function obj = embiggenMatrix(obj, varargin)
293294
% Enlarges data points of matrix for easier viewing. Also adds the network colorbars to the left axis and bottom axis.
294-
import nla.gfx.colorChunk nla.gfx.MatrixType nla.gfx.valToColor nla.gfx.drawLine
295+
import nla.gfx.colorChunk nla.gfx.MatrixType nla.gfx.drawLine
296+
297+
% If there are no inputs (like initial rendering) then we use defaults
298+
% If there were inputs, that means we're scaling the colorbar.
299+
if isempty(varargin)
300+
upper_value = obj.upper_limit;
301+
lower_value = obj.lower_limit;
302+
else
303+
upper_value = str2double(varargin{2});
304+
lower_value = str2double(varargin{1});
305+
end
295306
number_of_networks = obj.number_networks;
296307
dimensions = obj.image_dimensions;
297308
network_matrix = obj.network_matrix;
@@ -313,12 +324,7 @@ function addCallback(obj, x)
313324
chunk_height = numel(network_indexes) * obj.elementSize();
314325

315326
% Left side of matrix color bars
316-
top = position_y;
317-
bottom = position_y + chunk_height;
318-
left = dimensions("offset_x") + 2;
319-
right = dimensions("offset_x") + dimensions("label_size") + 1;
320-
obj.image_display.CData(top:bottom, left:right+1, :) = colorChunk(obj.networks(network).color, chunk_height + 1, dimensions("label_size") + 1);
321-
obj = obj.drawLeftLinesOnLabels(top, bottom, left, right);
327+
obj.drawLeftLinesOnLabels(position_y, chunk_height, dimensions, network);
322328

323329
position_x = dimensions("label_size") + dimensions("offset_x") + 3;
324330
starting_x = position_x;
@@ -336,34 +342,33 @@ function addCallback(obj, x)
336342

337343
chunk_width = numel(x_index) * obj.elementSize();
338344

339-
% Fill the chunk with a color mapped to its value
345+
% Get color for chunks
340346
chunk_raw = matrix_as_matrix(network_indexes, x_index);
341-
chunk = valToColor(chunk_raw, obj.lower_limit, obj.upper_limit, obj.color_map);
342-
chunk(isnan(chunk_raw)) = NaN; % puts all NaNs back removed with valToColor
347+
chunk_color = obj.getChunkColor(chunk_raw, upper_value, lower_value);
343348

344349
% Apply colors to chunks
345-
obj.image_display.CData(position_y:position_y + chunk_height - 1, position_x:position_x + chunk_width - 1, :) =...
346-
repelem(chunk, obj.elementSize(), obj.elementSize());
347-
obj.image_display.CData(position_y + chunk_height, position_x:position_x + chunk_width - 1, :) =...
348-
repelem(chunk(size(chunk, 1), 1:size(chunk, 2), :), 1, obj.elementSize());
349-
obj.image_display.CData(position_y:position_y + chunk_height - 1, position_x + chunk_width, :) =...
350-
repelem(chunk(1:size(chunk, 1), size(chunk, 2), :), obj.elementSize(), 1);
350+
obj.applyColorToData(position_x, position_y, chunk_height, chunk_width, chunk_color);
351351

352352
% plot signifance marker
353353
if ~isequal(obj.marked_networks, false) && isequal(obj.marked_networks(network, x), true)
354354
obj.plotSignificanceMark(chunk_width, chunk_height, position_x, position_y);
355355
end
356356

357357
if ~isequal(obj.network_clicked_callback, false)
358-
obj.network_dimensions(x, network, :) = [position_x, position_x + chunk_width - 1, position_y, position_y + chunk_height - 1];
358+
obj.network_dimensions(x, network, :) = [position_x, position_x + chunk_width - 1,...
359+
position_y, position_y + chunk_height - 1];
359360
end
360361
% Add callbacks to all the squares
361-
obj.addCallback(drawLine(obj.axes, [position_x - 1, position_x - 1], [position_y, position_y + chunk_height + 1]));
362-
obj.addCallback(drawLine(obj.axes, [position_x - 2, position_x + chunk_width - 1], [position_y + chunk_height, position_y + chunk_height]));
362+
obj.addCallback(drawLine(obj.axes, [position_x - 1, position_x - 1],...
363+
[position_y, position_y + chunk_height + 1]));
364+
obj.addCallback(drawLine(obj.axes, [position_x - 2, position_x + chunk_width - 1],...
365+
[position_y + chunk_height, position_y + chunk_height]));
363366

364367
if x == maximum_x && obj.matrix_type == MatrixType.TRIMATRIX && ~isequal(network_matrix, false)
365-
obj.addCallback(drawLine(obj.axes, [position_x + chunk_width, position_x + chunk_width], [position_y - 1, position_y + chunk_height + 1]));
366-
obj.addCallback(drawLine(obj.axes, [position_x - 2, position_x + chunk_width], [position_y - 1, position_y - 1]));
368+
obj.addCallback(drawLine(obj.axes, [position_x + chunk_width, position_x + chunk_width],...
369+
[position_y - 1, position_y + chunk_height + 1]));
370+
obj.addCallback(drawLine(obj.axes, [position_x - 2, position_x + chunk_width],...
371+
[position_y - 1, position_y - 1]));
367372
end
368373

369374
% Is this the last network of a TriMatrix. Then we're done and need to add the bottom
@@ -381,16 +386,24 @@ function addCallback(obj, x)
381386
end
382387
position_y = position_y + chunk_height + 1;
383388
end
384-
389+
385390
if obj.matrix_type == MatrixType.TRIMATRIX && ~network_matrix
386-
drawLine(obj.axes, [starting_x - 1, position_x - 1], [starting_y - 3 + obj.elementSize(), position_y - 2], 'w');
387-
drawLine(obj.axes, [starting_x - 2, position_x - 1], [starting_y - 3 + obj.elementSize(), position_y - 1]);
391+
drawLine(obj.axes, [starting_x - 1, position_x - 1],...
392+
[starting_y - 3 + obj.elementSize(), position_y - 2], 'w');
393+
drawLine(obj.axes, [starting_x - 2, position_x - 1],...
394+
[starting_y - 3 + obj.elementSize(), position_y - 1]);
388395
end
389396
end
390397

391-
function obj = drawLeftLinesOnLabels(obj, top, bottom, left, right)
398+
function drawLeftLinesOnLabels(obj, position_y, chunk_height, dimensions, network)
392399
% Draws the left side lines on the plot
393-
import nla.gfx.drawLine
400+
import nla.gfx.drawLine nla.gfx.colorChunk
401+
402+
top = position_y;
403+
bottom = position_y + chunk_height;
404+
left = dimensions("offset_x") + 2;
405+
right = dimensions("offset_x") + dimensions("label_size") + 1;
406+
obj.image_display.CData(top:bottom, left:right+1, :) = colorChunk(obj.networks(network).color, chunk_height + 1, dimensions("label_size") + 1);
394407

395408
drawLine(obj.axes, [left - 1, right], [top - 1, top - 1]);
396409
drawLine(obj.axes, [left - 1, right], [bottom, bottom]);
@@ -462,11 +475,23 @@ function createLegend(obj)
462475
display_legend_width, display_legend_height];
463476
end
464477

465-
function createColorbar(obj)
478+
function createColorbar(obj, varargin)
466479
% Creates the colorbar
467480
% Annoyance: obj.color_map is a property, colormap is a command. Same with color_bar and colorbar
481+
482+
% If there are arguments, it means that this came from changing the colorbar. If not, using defaults
483+
if isempty(varargin)
484+
upper_value = obj.upper_limit;
485+
lower_value = obj.lower_limit;
486+
else
487+
obj.color_bar.TickLabels = {};
488+
obj.color_bar.Ticks = [];
489+
upper_value = str2double(varargin{2});
490+
lower_value = str2double(varargin{1});
491+
end
492+
468493
if obj.discrete_colorbar
469-
number_of_ticks = double(obj.upper_limit - obj.lower_limit);
494+
number_of_ticks = double(upper_value - lower_value);
470495
display_colormap = obj.color_map(floor((size(obj.color_map, 1) - 1) * [0:number_of_ticks] ./ number_of_ticks) + 1, :);
471496
display_colormap = repelem(display_colormap, 2, 1);
472497
display_colormap = display_colormap(2:((number_of_ticks + 1) * 2 - 1), :);
@@ -477,16 +502,16 @@ function createColorbar(obj)
477502
end
478503

479504
obj.color_bar = colorbar(obj.axes);
480-
505+
481506
ticks = [0:number_of_ticks];
482507
obj.color_bar.Ticks = double(ticks) ./ number_of_ticks;
483508

484509
labels = {};
485510
for tick = ticks
486-
labels{tick + 1} = sprintf("%.2g", obj.lower_limit + (tick * ((double(obj.upper_limit - obj.lower_limit) / number_of_ticks))));
511+
labels{tick + 1} = sprintf("%.2g", lower_value + (tick * ((double(upper_value - lower_value) / number_of_ticks))));
487512
end
488513
obj.color_bar.TickLabels = labels;
489-
514+
490515
dimensions = obj.image_dimensions;
491516
obj.color_bar.Units = 'pixels';
492517
obj.color_bar.Location = 'east';
@@ -495,8 +520,48 @@ function createColorbar(obj)
495520
obj.color_bar.Position = [obj.color_bar.Position(1) - dimensions("offset_x"),...
496521
obj.color_bar.Position(2) + dimensions("offset_y"), obj.colorbar_width,...
497522
dimensions("image_height") - (dimensions("offset_y") * 2) - 20];
523+
obj.color_bar.Title.Position(2) = 0 - dimensions("offset_y") * 2 / 3;
524+
obj.color_bar.Title.String = sprintf("Click to\nchange scale\n");
525+
obj.color_bar.Title.FontSize = 7;
526+
527+
% Enables callback for clicking on colorbar to scale data
528+
set(obj.color_bar, 'ButtonDownFcn', @changeColorLimits)
498529

499530
caxis(obj.axes, [0, 1]);
531+
532+
533+
% Callback for clicking on the colorbar.
534+
function changeColorLimits(~, ~)
535+
prompt = {"Enter Lower Limit: ", "Enter Upper Limit: "};
536+
upper_limit_inner = obj.color_bar.TickLabels(end);
537+
lower_limit_inner = obj.color_bar.TickLabels(1);
538+
current_limits = {lower_limit_inner{1}, upper_limit_inner{1}};
539+
new_limits = inputdlg(prompt, "Colorbar Limits", 1, current_limits);
540+
% If "cancel" is pressed or both values deleted use defaults
541+
if isempty(new_limits) || isempty(new_limits{1}) || isempty(new_limits{2})
542+
obj.embiggenMatrix();
543+
obj.createColorbar();
544+
else
545+
obj.embiggenMatrix(new_limits{1}, new_limits{2});
546+
obj.createColorbar(new_limits{1}, new_limits{2});
547+
end
548+
end
549+
end
550+
551+
function chunk_color = getChunkColor(obj, chunk_raw, upper_value, lower_value)
552+
% Get color for the chunk (square)
553+
chunk_color = nla.gfx.valToColor(chunk_raw, lower_value, upper_value, obj.color_map);
554+
chunk_color(isnan(chunk_raw)) = NaN; % puts all NaNs back removed with valToColor
555+
end
556+
557+
function applyColorToData(obj, position_x, position_y, chunk_height, chunk_width, chunk_color)
558+
% Fill in the chunks (squares) with color
559+
obj.image_display.CData(position_y:position_y + chunk_height - 1, position_x:position_x + chunk_width - 1, :) =...
560+
repelem(chunk_color, obj.elementSize(), obj.elementSize());
561+
obj.image_display.CData(position_y + chunk_height, position_x:position_x + chunk_width - 1, :) =...
562+
repelem(chunk_color(size(chunk_color, 1), 1:size(chunk_color, 2), :), 1, obj.elementSize());
563+
obj.image_display.CData(position_y:position_y + chunk_height - 1, position_x + chunk_width, :) =...
564+
repelem(chunk_color(1:size(chunk_color, 1), size(chunk_color, 2), :), obj.elementSize(), 1);
500565
end
501566
end
502567
end

+nla/+gfx/ProbPlotMethod.m

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
classdef ProbPlotMethod
22
enumeration
3-
DEFAULT, LOG, NEG_LOG_10
3+
DEFAULT, LOG, NEG_LOG_10, STATISTIC
44
end
55
end
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
function saveErrorObjInTimestampedMatfile(saveFolder, errorObj)
2+
3+
nowTime = datetime;
4+
nowTime.Format = 'yyyyMMdd-hhmmss';
5+
6+
errFilename = sprintf('error_%s.mat',nowTime);
7+
errFullFilename = fullfile(saveFolder, errFilename);
8+
9+
save(errFullFilename, 'errorObj');
10+
11+
end

0 commit comments

Comments
 (0)