From 884e7540532a99abc59428c983f467ddb681b77d Mon Sep 17 00:00:00 2001 From: Jim Pollaro Date: Thu, 2 Jul 2026 11:59:53 -0500 Subject: [PATCH 1/9] added scaling and colormap choice to chords --- +nla/+net/+result/+chord/ChordPlotter.m | 112 +++++++++++++++++++++++- 1 file changed, 110 insertions(+), 2 deletions(-) diff --git a/+nla/+net/+result/+chord/ChordPlotter.m b/+nla/+net/+result/+chord/ChordPlotter.m index 27272895..32dce50e 100644 --- a/+nla/+net/+result/+chord/ChordPlotter.m +++ b/+nla/+net/+result/+chord/ChordPlotter.m @@ -9,6 +9,8 @@ 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 @@ -16,6 +18,7 @@ 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 @@ -35,6 +38,9 @@ function generateChordFigure(obj, parameters, chord_type) 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 @@ -68,15 +74,21 @@ 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) else % Plot edge chord obj.generateEdgeChordFigure(plot_figure, parameters, chord_type) end + + 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 end @@ -199,5 +211,101 @@ function generateEdgeChordFigure(obj, plot_figure, parameters, chord_type) end color_bar.TickLabels = labels; 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 = ' '; + 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 '__']; + end + new_html_end = [new_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) + + close(plot_figure); + close(src.Parent); + end end end \ No newline at end of file From b94a69791223f713ca673d7fab6f9119c6378b92 Mon Sep 17 00:00:00 2001 From: Jim Pollaro Date: Mon, 6 Jul 2026 11:23:17 -0500 Subject: [PATCH 2/9] hopefully centering plots together --- +nla/+net/+result/+chord/ChordPlotter.m | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/+nla/+net/+result/+chord/ChordPlotter.m b/+nla/+net/+result/+chord/ChordPlotter.m index 32dce50e..56e9e9fa 100644 --- a/+nla/+net/+result/+chord/ChordPlotter.m +++ b/+nla/+net/+result/+chord/ChordPlotter.m @@ -33,7 +33,7 @@ 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 @@ -59,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" @@ -302,7 +305,7 @@ function applyScale(obj, src, ~, upper_limit_box, lower_limit_box, color_map, pl parameters.color_map_name = color_map; end - obj.generateChordFigure(parameters, chord_type) + obj.generateChordFigure(parameters, chord_type, plot_figure) close(plot_figure); close(src.Parent); From dcbb1f862635b211740e146a2027251aba594f39 Mon Sep 17 00:00:00 2001 From: Github Action Date: Mon, 6 Jul 2026 16:23:38 +0000 Subject: [PATCH 3/9] Exported mlapp files --- +nla/+net/+result/+plot/NetworkTestPlotApp_exported.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/+nla/+net/+result/+plot/NetworkTestPlotApp_exported.m b/+nla/+net/+result/+plot/NetworkTestPlotApp_exported.m index ba7b11aa..7b1529c1 100644 --- a/+nla/+net/+result/+plot/NetworkTestPlotApp_exported.m +++ b/+nla/+net/+result/+plot/NetworkTestPlotApp_exported.m @@ -322,7 +322,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, From 90c95b62240fe1ced558faefdd252fd35b5d1b07 Mon Sep 17 00:00:00 2001 From: Jim Pollaro Date: Mon, 6 Jul 2026 16:24:35 -0500 Subject: [PATCH 4/9] edge chord scaling --- +nla/+net/+result/+chord/ChordPlotter.m | 80 ++++++++++++++++++------- 1 file changed, 58 insertions(+), 22 deletions(-) diff --git a/+nla/+net/+result/+chord/ChordPlotter.m b/+nla/+net/+result/+chord/ChordPlotter.m index 56e9e9fa..819416c7 100644 --- a/+nla/+net/+result/+chord/ChordPlotter.m +++ b/+nla/+net/+result/+chord/ChordPlotter.m @@ -82,27 +82,33 @@ function generateChordFigure(obj, parameters, chord_type, parent_figure) coefficient_bounds(2), 'lower_limit', coefficient_bounds(1), 'chord_type', chord_type); 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 - 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 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; @@ -125,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; @@ -149,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() @@ -180,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); @@ -192,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'; @@ -213,6 +243,12 @@ 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) From af8e21fcb7bbb53a2ff739872ba98afc95ac2378 Mon Sep 17 00:00:00 2001 From: Jim Pollaro Date: Mon, 20 Jul 2026 13:42:37 -0500 Subject: [PATCH 5/9] moved color and scale modals to seperate functions --- +nla/+gfx/colorSelector.m | 46 ++++++++++++++++ +nla/+gfx/scaleSelector.m | 28 ++++++++++ +nla/+net/+result/+chord/ChordPlotter.m | 72 +------------------------ 3 files changed, 76 insertions(+), 70 deletions(-) create mode 100644 +nla/+gfx/colorSelector.m create mode 100644 +nla/+gfx/scaleSelector.m diff --git a/+nla/+gfx/colorSelector.m b/+nla/+gfx/colorSelector.m new file mode 100644 index 00000000..5e1f00cd --- /dev/null +++ b/+nla/+gfx/colorSelector.m @@ -0,0 +1,46 @@ +function colorSelector(src, plot_figure, plot_parameters, chord_type, callback_function, color_choices) + original_figure = src.Parent.Parent; + modal = figure('WindowStyle', 'normal', 'Units', 'pixels', 'Position',... + [original_figure.Position(1), original_figure.Position(2), original_figure.Position(3) / 2, original_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(color_choices) + colormap_function = str2func(strcat(strcat("@(x) ",lower(color_choices{colors})), "(x)")); + CData = colormap_function(initial_colors); + new_html_start = ' '; + 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 '__']; + end + new_html_end = [new_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", {callback_function, 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 \ No newline at end of file diff --git a/+nla/+gfx/scaleSelector.m b/+nla/+gfx/scaleSelector.m new file mode 100644 index 00000000..c4d7c46a --- /dev/null +++ b/+nla/+gfx/scaleSelector.m @@ -0,0 +1,28 @@ +function scaleSelector(src, bounds, plot_figure, parameters, chord_type, callback_function) + original_figure = src.Parent.Parent; + modal = figure('WindowStyle', 'normal', 'Units', 'pixels', 'Position',... + [original_figure.Position(1), original_figure.Position(2), original_figure.Position(3) / 3, original_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", {callback_function, 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 \ No newline at end of file diff --git a/+nla/+net/+result/+chord/ChordPlotter.m b/+nla/+net/+result/+chord/ChordPlotter.m index 819416c7..0e93533b 100644 --- a/+nla/+net/+result/+chord/ChordPlotter.m +++ b/+nla/+net/+result/+chord/ChordPlotter.m @@ -252,79 +252,11 @@ function generateEdgeChordFigure(obj, plot_figure, parameters, chord_type, paren 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); + nla.gfx.scaleSelector(src, bounds, plot_figure, parameters, chord_type, @obj.applyScale); 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 = ' '; - 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 '__']; - end - new_html_end = [new_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); + nla.gfx.colorSelector(src, plot_figure, parameters, chord_type, @obj.applyScale, obj.colormap_choices); end function applyScale(obj, src, ~, upper_limit_box, lower_limit_box, color_map, plot_figure, parameters, chord_type) From 0880c3d442fb7f0b6494ef7598c99e398c941ae8 Mon Sep 17 00:00:00 2001 From: Jim Pollaro Date: Mon, 20 Jul 2026 15:06:16 -0500 Subject: [PATCH 6/9] trying to put colormap select and scale to non-app matrix plot --- +nla/+gfx/+plots/MatrixPlot.m | 30 ++++++++++++++++++++++--- +nla/+inputField/NetworkAtlasFuncConn.m | 3 ++- 2 files changed, 29 insertions(+), 4 deletions(-) diff --git a/+nla/+gfx/+plots/MatrixPlot.m b/+nla/+gfx/+plots/MatrixPlot.m index 0b90ec04..6a01a723 100644 --- a/+nla/+gfx/+plots/MatrixPlot.m +++ b/+nla/+gfx/+plots/MatrixPlot.m @@ -35,6 +35,7 @@ current_settings % the settings for the plot (upper, lower, scale) display_legend p_value_max + app_plot % Used when called for FC Avg end properties (Dependent) @@ -112,12 +113,13 @@ addParameter(matrix_input_parser, 'y_position', 0, validNumberInput); addParameter(matrix_input_parser, 'discrete_colorbar', false, @islogical); addParameter(matrix_input_parser, 'plot_scale', nla.gfx.ProbPlotMethod.DEFAULT); - addParameter(matrix_input_parser, 'p_value_max', 0.05) + addParameter(matrix_input_parser, 'p_value_max', 0.05); + addParameter(matrix_input_parser, 'app_plot', true, @islogical) parse(matrix_input_parser, figure, name, matrix, networks, figure_size, varargin{:}); properties = {'figure', 'name', 'matrix', 'networks', 'figure_size', 'network_clicked_callback',... 'marked_networks', 'figure_margins', 'draw_legend', 'draw_colorbar', 'color_map', 'lower_limit',... - 'upper_limit', 'x_position', 'y_position', 'discrete_colorbar', 'plot_scale', 'p_value_max'}; + 'upper_limit', 'x_position', 'y_position', 'discrete_colorbar', 'plot_scale', 'p_value_max', 'app_plot'}; for property = properties obj.(property{1}) = matrix_input_parser.Results.(property{1}); if property{1} == "marked_networks" @@ -182,6 +184,18 @@ function displayImage(obj) 'HorizontalAlignment', 'center'); end + if isequal(obj.app_plot, false) + settings_menu = uimenu(obj.figure, 'Text', 'Settings'); + change_scale_option = uimenu(settings_menu,'Text','Change Scale'); + change_scale_option.MenuSelectedFcn = {... + @obj.adjustScale, [obj.lower_limit, obj.upper_limit], obj.figure,... + struct('lower_bound', obj.lower_limit, 'upper_bound', obj.upper_limit, 'p_value_plot_max', obj.p_value_max),... + false... + }; + change_color_map = uimenu(settings_menu, 'Text', 'Change Color Map'); + change_color_map.MenuSelectedFcn = {@obj.adjustColor, obj.figure, struct('color_map', obj.color_map, 'color_map_name', ""), false}; + end + obj.fixRendering(); hold(obj.axes, 'off') % This may have been turned on. Does nothing if it wasn't. @@ -337,7 +351,7 @@ function removeLegend(obj) image_height = image_height + 20; end - % colorbar margins + % colorbar marginsobj if obj.draw_colorbar image_width = image_width + obj.colorbar_width + obj.colorbar_offset + obj.colorbar_text_w; end @@ -677,5 +691,15 @@ function applyColorToData(obj, position_x, position_y, chunk_height, chunk_width obj.image_display.CData(position_y:position_y + chunk_height - 1, position_x + chunk_width, :) =... repelem(chunk_color(1:size(chunk_color, 1), size(chunk_color, 2), :), obj.elementSize(), 1); end + + function adjustScale(obj, src, ~, bounds, plot_figure, parameters, chord_type) + nla.gfx.scaleSelector(src, bounds, plot_figure, parameters, chord_type, @obj.applyScale); + end + + function adjustColor(obj, src, ~, plot_figure, parameters, chord_type) + nla.gfx.colorSelector(src, plot_figure, parameters, chord_type, @obj.applyScale, obj.colormap_choices); + end + + end end diff --git a/+nla/+inputField/NetworkAtlasFuncConn.m b/+nla/+inputField/NetworkAtlasFuncConn.m index 0f1a47f8..775bc08d 100755 --- a/+nla/+inputField/NetworkAtlasFuncConn.m +++ b/+nla/+inputField/NetworkAtlasFuncConn.m @@ -322,8 +322,9 @@ function buttonViewFCAvgClickedCallback(obj) fc_avg = copy(obj.func_conn); fc_avg.v = mean(fc_avg.v, 2); fig_l = nla.gfx.createFigure(); + matrix_plot = nla.gfx.plots.MatrixPlot(fig_l, 'FC Average (Fisher Z(R))', fc_avg, obj.net_atlas.nets,... - nla.gfx.FigSize.LARGE); + nla.gfx.FigSize.LARGE, "app_plot", false); fig_l.Position(3) = matrix_plot.image_dimensions("image_width"); fig_l.Position(4) = matrix_plot.image_dimensions("image_height"); matrix_plot.displayImage(); From 1d31a76fb39b20cf5a496ae8b41d7a67d823248a Mon Sep 17 00:00:00 2001 From: Jim Pollaro Date: Mon, 27 Jul 2026 11:22:49 -0500 Subject: [PATCH 7/9] added lots of str2double --- +nla/+gfx/+plots/MatrixPlot.m | 40 +++++++++++++++++++++++++---------- 1 file changed, 29 insertions(+), 11 deletions(-) diff --git a/+nla/+gfx/+plots/MatrixPlot.m b/+nla/+gfx/+plots/MatrixPlot.m index 6a01a723..3873d0ee 100644 --- a/+nla/+gfx/+plots/MatrixPlot.m +++ b/+nla/+gfx/+plots/MatrixPlot.m @@ -210,7 +210,7 @@ function applyScale(obj, ~, ~, upper_limit_box, lower_limit_box, old_scale, new_ obj.color_bar.Ticks = []; color_map = color_map_select; - if ~isstring(color_map_select) && ~ischar(color_map_select) + if ~isstring(color_map_select) && ~ischar(color_map_select) && ~isequal(color_map, false) color_map = get(color_map_select, "Value"); color_map = obj.colormap_choices{color_map}; end @@ -221,13 +221,20 @@ function applyScale(obj, ~, ~, upper_limit_box, lower_limit_box, old_scale, new_ if isnumeric(upper_limit_box) obj.upper_limit = upper_limit_box; else - obj.upper_limit = get(upper_limit_box, "String"); + obj.upper_limit = get(upper_limit_box, 'String'); end if isnumeric(lower_limit_box) obj.lower_limit = lower_limit_box; else - obj.lower_limit = get(lower_limit_box, "String"); + obj.lower_limit = get(lower_limit_box, 'String'); + end + + if isstring(obj.upper_limit) || ischar(obj.upper_limit) + obj.upper_limit = str2double(obj.upper_limit); + end + if isstring(obj.lower_limit) || ischar(obj.lower_limit) + obj.lower_limit = str2double(obj.lower_limit); end if ~isstring(obj.plot_scale) @@ -253,7 +260,11 @@ function applyScale(obj, ~, ~, upper_limit_box, lower_limit_box, old_scale, new_ discrete_colors = NetworkResultPlotParameter().default_discrete_colors; if new_scale == "nla.gfx.ProbPlotMethod.DEFAULT" - new_color_map = NetworkResultPlotParameter.getColormap(discrete_colors, obj.upper_limit, color_map); + if ~isequal(color_map, false) + new_color_map = NetworkResultPlotParameter.getColormap(discrete_colors, obj.upper_limit, color_map); + else + new_color_map = obj.color_map; + end obj.plot_scale = new_scale; elseif new_scale == "nla.gfx.ProbPlotMethod.LOG" new_color_map = NetworkResultPlotParameter.getLogColormap(discrete_colors, obj.matrix, obj.upper_limit, color_map); @@ -449,10 +460,10 @@ function addCallback(obj, x) initial_render = false; upper_value = varargin{2}; lower_value = varargin{1}; - if isstring(upper_value) + if isstring(upper_value) || ischar(upper_value) % why are strings not chars??? upper_value = str2double(upper_value); end - if isstring(lower_value) + if isstring(lower_value) || ischar(lower_value) lower_value = str2double(lower_value); end end @@ -692,14 +703,21 @@ function applyColorToData(obj, position_x, position_y, chunk_height, chunk_width repelem(chunk_color(1:size(chunk_color, 1), size(chunk_color, 2), :), obj.elementSize(), 1); end - function adjustScale(obj, src, ~, bounds, plot_figure, parameters, chord_type) - nla.gfx.scaleSelector(src, bounds, plot_figure, parameters, chord_type, @obj.applyScale); + function adjustScale(obj, src, ~, bounds, plot_figure, parameters, ~) + nla.gfx.scaleSelector(src, bounds, plot_figure, parameters, false, @obj.applyScaleWrapper); end - function adjustColor(obj, src, ~, plot_figure, parameters, chord_type) - nla.gfx.colorSelector(src, plot_figure, parameters, chord_type, @obj.applyScale, obj.colormap_choices); + function adjustColor(obj, src, ~, plot_figure, parameters, ~) + nla.gfx.colorSelector(src, plot_figure, parameters, false, @obj.applyScaleWrapper, obj.colormap_choices); end - + function applyScaleWrapper(obj, ~, ~, upper_limit_box, lower_limit_box, color_map, ~, ~, ~) + % This is used for the edge trimatrix, fc avg which is why we keep the ProbPlotMethod to DEFAULT + if isequal(upper_limit_box, false) + upper_limit_box = obj.upper_limit; + lower_limit_box = obj.lower_limit; + end + obj.applyScale(false, false, upper_limit_box, lower_limit_box, "nla.gfx.ProbPlotMethod.DEFAULT", "nla.gfx.ProbPlotMethod.DEFAULT", color_map) + end end end From e7ae4d3a17adf6a593954d1a4ef4cb2958332d1b Mon Sep 17 00:00:00 2001 From: Jim Pollaro Date: Mon, 27 Jul 2026 11:28:42 -0500 Subject: [PATCH 8/9] added scaling setting for edge matrix plot --- +nla/+edge/+result/Base.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/+nla/+edge/+result/Base.m b/+nla/+edge/+result/Base.m index 39de0ad0..e582cf2a 100755 --- a/+nla/+edge/+result/Base.m +++ b/+nla/+edge/+result/Base.m @@ -44,7 +44,7 @@ function output(obj, net_atlas, flags, prob_label) fig = nla.gfx.createFigure(); matrix_plot = nla.gfx.plots.MatrixPlot(fig, coeff_label, obj.coeff, net_atlas.nets, nla.gfx.FigSize.LARGE, 'lower_limit', obj.coeff_range(1),... - 'upper_limit', obj.coeff_range(2)); + 'upper_limit', obj.coeff_range(2), 'app_plot', false); matrix_plot.displayImage(); w = matrix_plot.image_dimensions("image_width"); h = matrix_plot.image_dimensions("image_height"); From 04a90c8357bbabe00d10e4586ae3d4140ba78d0b Mon Sep 17 00:00:00 2001 From: Github Action Date: Mon, 27 Jul 2026 16:34:34 +0000 Subject: [PATCH 9/9] Exported mlapp files --- +nla/+net/+result/+plot/NetworkTestPlotApp_exported.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/+nla/+net/+result/+plot/NetworkTestPlotApp_exported.m b/+nla/+net/+result/+plot/NetworkTestPlotApp_exported.m index 7b1529c1..ba7b11aa 100644 --- a/+nla/+net/+result/+plot/NetworkTestPlotApp_exported.m +++ b/+nla/+net/+result/+plot/NetworkTestPlotApp_exported.m @@ -322,7 +322,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, false) + chord_plotter.generateChordFigure(probability_parameters, plot_type) end % Value changed function: ColormapDropDown,