Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
187 changes: 167 additions & 20 deletions +nla/+net/+result/+chord/ChordPlotter.m
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,16 @@
axis_width = 750; % Constant for the size of the chord
trimatrix_width = 500; % Constant for the size of the Trimatrix plotted with
bottom_text_height = 250; % How far from the bottom of the trimatrix the text appears
colormap_choices = {"Parula", "Turbo", "HSV", "Hot", "Cool", "Spring", "Summer", "Autumn", "Winter", "Gray",...
"Bone", "Copper", "Pink"}; % Colorbar choices
end

properties
network_atlas % Network Atlas for the data
edge_test_result % Edge test results
split_plot = false % This is an option that is set automatically during operation.
edge_plot_type = "nla.gfx.EdgeChordPlotMethod.PROB" % Default chord type for edges
chord_plotter = false
end

methods
Expand All @@ -30,11 +33,14 @@
end
end

function generateChordFigure(obj, parameters, chord_type)
function generateChordFigure(obj, parameters, chord_type, parent_figure)
% generateChordFigure plots chords for a network test
import nla.gfx.SigType nla.net.result.plot.PermutationTestPlotter nla.gfx.EdgeChordPlotMethod nla.gfx.setTitle

coefficient_bounds = [0, parameters.p_value_plot_max];
if isfield(parameters, "lower_bound")
coefficient_bounds(1) = parameters.lower_bound;
end
if parameters.significance_type == SigType.INCREASING && parameters.p_value_plot_max < 1
coefficient_bounds = [parameters.p_value_plot_max, 1];
end
Expand All @@ -53,6 +59,9 @@ function generateChordFigure(obj, parameters, chord_type)
else
plot_figure = nla.gfx.createFigure(obj.axis_width , obj.axis_width);
end
if ~isequal(parent_figure, false)
nla.gfx.moveFigToParentUILocation(plot_figure, parent_figure);
end

% Plot a standard chord plot
if chord_type == "nla.PlotType.CHORD"
Expand All @@ -68,26 +77,38 @@ function generateChordFigure(obj, parameters, chord_type)
% thresholding below the "insignificance" value
statistic_matrix = copy(parameters.statistic_plot_matrix);
statistic_matrix.v(~parameters.significance_plot.v) = insignificance;
chord_plotter = nla.gfx.chord.ChordPlot(obj.network_atlas, figure_axis, 500, statistic_matrix,...
obj.chord_plotter = nla.gfx.chord.ChordPlot(obj.network_atlas, figure_axis, 500, statistic_matrix,...
'color_map', parameters.color_map, 'direction', parameters.significance_type, 'upper_limit',...
coefficient_bounds(2), 'lower_limit', coefficient_bounds(1), 'chord_type', chord_type);
chord_plotter.drawChords();
obj.chord_plotter.drawChords();
setTitle(figure_axis, parameters.name_label)
settings_menu = uimenu(plot_figure, 'Text', 'Settings');
change_scale_option = uimenu(settings_menu,'Text','Change Scale');
change_scale_option.MenuSelectedFcn = {@obj.adjustScale, coefficient_bounds, plot_figure, parameters, chord_type};
change_color_map = uimenu(settings_menu, 'Text', 'Change Color Map');
change_color_map.MenuSelectedFcn = {@obj.adjustColor, plot_figure, parameters, chord_type};
else
% Plot edge chord
obj.generateEdgeChordFigure(plot_figure, parameters, chord_type)
obj.generateEdgeChordFigure(plot_figure, parameters, chord_type, parent_figure)
end


end
end

methods (Access = protected)
function generateEdgeChordFigure(obj, plot_figure, parameters, chord_type)
function generateEdgeChordFigure(obj, plot_figure, parameters, chord_type, parent_figure)
% generateEdgeChordFigure generates the edge chord plotting
import nla.gfx.EdgeChordPlotMethod nla.gfx.setTitle

range_limit = std(obj.edge_test_result.coeff.v) * 5;
coefficient_min = -range_limit;
coefficient_max = range_limit;
if isfield(parameters, "lower_bound")
coefficient_min = parameters.lower_bound;
coefficient_max = parameters.p_value_plot_max;
else
range_limit = std(obj.edge_test_result.coeff.v) * 5;
coefficient_min = -range_limit;
coefficient_max = range_limit;
end

clipped_values = nla.TriMatrix(obj.network_atlas.numROIs(), nla.TriMatrixDiag.REMOVE_DIAGONAL);
clipped_values.v = obj.edge_test_result.coeff.v;
Expand All @@ -110,21 +131,39 @@ function generateEdgeChordFigure(obj, plot_figure, parameters, chord_type)
switch obj.edge_plot_type
case "nla.gfx.EdgeChordPlotMethod.COEFF"
main_title = positive_title;
if isfield(parameters, "lower_bound")
coefficient_min = parameters.lower_bound;
coefficient_max = parameters.p_value_plot_max;
end

case "nla.gfx.EdgeChordPlotMethod.COEFF_SPLIT"
main_title = negative_title;
positive_main_title = positive_title;
if isfield(parameters, "lower_bound")
coefficient_min = parameters.lower_bound;
coefficient_max = parameters.p_value_plot_max;
end

case "nla.gfx.EdgeChordPlotMethod.COEFF_BASE_SPLIT"
coefficient_min = obj.edge_test_result.coeff_range(1);
coefficient_max = obj.edge_test_result.coeff_range(2);
if isfield(parameters, "lower_bound")
coefficient_min = parameters.lower_bound;
coefficient_max = parameters.p_value_plot_max;
else
coefficient_min = obj.edge_test_result.coeff_range(1);
coefficient_max = obj.edge_test_result.coeff_range(2);
end

main_title = negative_title;
positive_main_title = positive_title;

case "nla.gfx.edgeChordPlotMethod.COEFF_BASE"
coefficient_min = obj.edge_test_result.coeff_range(1);
coefficient_max = obj.edge_test_result.coeff_range(2);
if isfield(parameters, "lower_bound")
coefficient_min = parameters.lower_bound;
coefficient_max = parameters.p_value_plot_max;
else
coefficient_min = obj.edge_test_result.coeff_range(1);
coefficient_max = obj.edge_test_result.coeff_range(2);
end

main_title = positive_title;

Expand All @@ -134,13 +173,19 @@ function generateEdgeChordFigure(obj, plot_figure, parameters, chord_type)

clipped_values.v = obj.edge_test_result.prob.v;
significance_type = "nla.gfx.SigType.DECREASING";
coefficient_min = 0;
coefficient_max = obj.edge_test_result.prob_max;
if isfield(parameters, "lower_bound")
coefficient_min = parameters.lower_bound;
coefficient_max = parameters.p_value_plot_max;
else
coefficient_min = 0;
coefficient_max = obj.edge_test_result.prob_max;
end

insignificance = 1;
main_title = sprintf("Edge-level P-values (P < %g) (Within Significant Net-Pair)",...
obj.edge_test_result.prob_max);
end
coefficient_bounds = [coefficient_min, coefficient_max];

% Filtering/Thresholding out values
for network1 = 1:obj.network_atlas.numNets()
Expand All @@ -165,8 +210,8 @@ function generateEdgeChordFigure(obj, plot_figure, parameters, chord_type)
obj.edge_plot_type == "nla.gfx.EdgeChordPlotMethod.COEFF_SPLIT" || obj.edge_plot_type == "nla.gfx.EdgeChordPlotMethod.COEFF_BASE_SPLIT"...
)
positive_chord_plotter = nla.gfx.chord.ChordPlot(obj.network_atlas, plot_axis, 450, clipped_values_positive,...
'direction', significance_type, 'chord_type', chord_type, 'color_map', color_map, 'lower_limit',...
coefficient_min, 'upper_limit', coefficient_max);
'direction', significance_type, 'chord_type', chord_type, 'color_map', parameters.color_map, 'lower_limit',...
coefficient_bounds(1), 'upper_limit', coefficient_bounds(2));
positive_chord_plotter.drawChords();
setTitle(plot_axis, positive_main_title);

Expand All @@ -177,12 +222,12 @@ function generateEdgeChordFigure(obj, plot_figure, parameters, chord_type)
plot_axis.Visible = true;
end

chord_plotter = nla.gfx.chord.ChordPlot(obj.network_atlas, plot_axis, 450, clipped_values, 'chord_type', chord_type,...
'direction', significance_type, 'color_map', color_map, 'lower_limit', coefficient_min, 'upper_limit', coefficient_max);
chord_plotter.drawChords();
obj.chord_plotter = nla.gfx.chord.ChordPlot(obj.network_atlas, plot_axis, 450, clipped_values, 'chord_type', chord_type,...
'direction', significance_type, 'color_map', parameters.color_map, 'lower_limit', coefficient_bounds(1), 'upper_limit', coefficient_bounds(2));
obj.chord_plotter.drawChords();
setTitle(plot_axis, main_title);

colormap(plot_axis, color_map);
colormap(plot_axis, parameters.color_map);
color_bar = colorbar(plot_axis);
color_bar.Units = 'pixels';
color_bar.Location = 'east';
Expand All @@ -198,6 +243,108 @@ function generateEdgeChordFigure(obj, plot_figure, parameters, chord_type)
labels{tick + 1} = sprintf("%.2g", coefficient_min + (tick * ((coefficient_max - coefficient_min) / number_ticks)));
end
color_bar.TickLabels = labels;

settings_menu = uimenu(plot_figure, 'Text', 'Settings');
change_scale_option = uimenu(settings_menu,'Text','Change Scale');
change_scale_option.MenuSelectedFcn = {@obj.adjustScale, coefficient_bounds, plot_figure, parameters, chord_type};
change_color_map = uimenu(settings_menu, 'Text', 'Change Color Map');
change_color_map.MenuSelectedFcn = {@obj.adjustColor, plot_figure, parameters, chord_type};
end

function adjustScale(obj, src, ~, bounds, plot_figure, parameters, chord_type)
chord_figure = src.Parent.Parent;
modal = figure('WindowStyle', 'normal', 'Units', 'pixels', 'Position',...
[chord_figure.Position(1), chord_figure.Position(2), chord_figure.Position(3) / 3, chord_figure.Position(4) / 3]);

upper_limit_box = uicontrol('Style', 'edit', "Units", "pixels", 'Position', [90, 130, 100, 30], "String",...
bounds(2));
upper_limit_box.Position(4) = upper_limit_box.FontSize * 2;
lower_limit_box = uicontrol('Style', 'edit', "Units", "pixels", 'Position', [90, 100, 100, 30], "String",...
bounds(1));
lower_limit_box.Position(4) = lower_limit_box.FontSize * 2;

uicontrol('Style', 'text', 'String', 'Upper Limit', "Units", "pixels", 'Position',...
[upper_limit_box.Position(1) - 80, upper_limit_box.Position(2) - 2, 80, upper_limit_box.Position(4)]);
uicontrol('Style', 'text', 'String', 'Lower Limit', "Units", "pixels", 'Position',...
[lower_limit_box.Position(1) - 80, lower_limit_box.Position(2) - 2, 80, lower_limit_box.Position(4)]);

apply_button_position = [10, 10, 100, 30];
apply_button = uicontrol('String', 'Apply',...
"Callback", {@obj.applyScale, upper_limit_box, lower_limit_box, false, plot_figure, parameters, chord_type},...
"Units", "pixels",...
'Position', apply_button_position);

close_button_position = [apply_button.Position(1) + apply_button.Position(3) + 10,...
apply_button.Position(2), apply_button.Position(3), apply_button.Position(4)];
uicontrol('String', 'Close', 'Callback', @(~, ~)close(modal), "Units", "pixels", 'Position',...
close_button_position);
end

function adjustColor(obj, src, ~, plot_figure, parameters, chord_type)
chord_figure = src.Parent.Parent;
modal = figure('WindowStyle', 'normal', 'Units', 'pixels', 'Position',...
[chord_figure.Position(1), chord_figure.Position(2), chord_figure.Position(3) / 2, chord_figure.Position(4) / 3]);

% Color Map selector
% Adapted from colormap-dropdown: https://www.mathworks.com/matlabcentral/fileexchange/43659-colormap-dropdown-menu

color_map_select = uicontrol('Style', 'popupmenu',...
'Position', [90, 130, 275, 30], "Units", "pixels",...
'FontName', 'Courier');
uicontrol("Style", "text", "string", "Colormaps", "Units", "pixels",...
"Position", [color_map_select.Position(1) - 80, color_map_select.Position(2) - 2, 80, color_map_select.Position(4)]);
initial_colors = 16;
colormap_html = {};
for colors = 1:numel(obj.colormap_choices)
colormap_function = str2func(strcat(strcat("@(x) ",lower(obj.colormap_choices{colors})), "(x)"));
CData = colormap_function(initial_colors);
new_html_start = '<HTML> ';
new_html = '';
for color_iterator = initial_colors:-1:1
hex_code = nla.gfx.rgb2hex([CData(color_iterator, 1), CData(color_iterator, 2),...
CData(color_iterator, 3)]);
new_html = [new_html '<FONT bgcolor="' hex_code ' "color="' hex_code '">__</FONT>'];
end
new_html_end = [new_html ' </HTML>'];
new_html = [new_html_start new_html_end];
colormap_html = [colormap_html; new_html];
end

if ~isfield(parameters, "color_map_name")
parameters.color_map_name = 1;
end
set(color_map_select, "Value", parameters.color_map_name, "String", colormap_html);

apply_button_position = [10, 10, 100, 30];
apply_button = uicontrol('String', 'Apply',...
"Callback", {@obj.applyScale, false, false, color_map_select, plot_figure, parameters, chord_type},...
"Units", "pixels",...
'Position', apply_button_position);

close_button_position = [apply_button.Position(1) + apply_button.Position(3) + 10,...
apply_button.Position(2), apply_button.Position(3), apply_button.Position(4)];
uicontrol('String', 'Close', 'Callback', @(~, ~)close(modal), "Units", "pixels", 'Position',...
close_button_position);
end

function applyScale(obj, src, ~, upper_limit_box, lower_limit_box, color_map, plot_figure, parameters, chord_type)

if ~isequal(upper_limit_box, false)
parameters.p_value_plot_max = str2double(get(upper_limit_box, "String"));
parameters.lower_bound = str2double(get(lower_limit_box, "String"));
end

if ~isequal(color_map, false)
color_map = get(color_map, "Value");
color_map_name = str2func(lower(obj.colormap_choices{color_map}));
parameters.color_map = color_map_name(1000);
parameters.color_map_name = color_map;
end

obj.generateChordFigure(parameters, chord_type, plot_figure)

close(plot_figure);
close(src.Parent);
end
end
end
Binary file modified +nla/+net/+result/+plot/NetworkTestPlotApp.mlapp
Binary file not shown.
2 changes: 1 addition & 1 deletion +nla/+net/+result/+plot/NetworkTestPlotApp_exported.m
Original file line number Diff line number Diff line change
Expand Up @@ -285,7 +285,7 @@ function drawChords(app, event)
chord_plotter = nla.net.result.chord.ChordPlotter(app.edge_test_options.net_atlas, app.edge_test_result);

probability_parameters.edge_chord_plot_method = app.EdgeChordPlotTypeDropDown.Value;
chord_plotter.generateChordFigure(probability_parameters, plot_type)
chord_plotter.generateChordFigure(probability_parameters, plot_type, false)
end

% Value changed function: ColormapDropDown,
Expand Down
Loading