Skip to content
Merged
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
195 changes: 137 additions & 58 deletions +nla/+gfx/+plots/MatrixPlot.m
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
axes % The axes of the plot
image_display % The actual displayed values
color_bar % The colorbar
colorbar_contextmenu % The right click menu for the colorbar
plot_scale % The scale and values being plotted (Linear, log, -log10, p-value, statistic p-value)
end

properties (Dependent)
Expand Down Expand Up @@ -74,6 +74,7 @@
% x_position = 0
% y_position = 0
% discrete_colorbar = false
% plot_scale = nla.gfx.ProbPlotMethod.DEFAULT
import nla.gfx.createFigure
matrix_input_parser = inputParser;
addRequired(matrix_input_parser, 'figure');
Expand All @@ -95,11 +96,12 @@
addParameter(matrix_input_parser, 'x_position', 0, validNumberInput);
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, @isenum);

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'};
'x_position', 'y_position', 'discrete_colorbar', 'plot_scale'};
for property = properties
obj.(property{1}) = matrix_input_parser.Results.(property{1});
if property{1} == "marked_networks"
Expand Down Expand Up @@ -217,7 +219,8 @@ function displayImage(obj)

dimensions = [image_height image_width offset_x offset_y plot_width plot_height display_matrix_size label_size];
% Matlab does not have a python-like dictionary. This is one, or a struct.
value = containers.Map(["image_height" "image_width" "offset_x" "offset_y" "plot_width" "plot_height" "display_matrix_size" "label_size"], dimensions);
value = containers.Map(["image_height" "image_width" "offset_x" "offset_y" "plot_width" "plot_height"...
"display_matrix_size" "label_size"], dimensions);
end

function value = get.as_matrix(obj)
Expand Down Expand Up @@ -254,7 +257,8 @@ function displayImage(obj)

function obj = drawAxes(obj)
% Creates the axes for the plot.
obj.axes = uiaxes(obj.figure, 'Position', [obj.x_position, obj.y_position, obj.image_dimensions("image_width"), obj.image_dimensions("image_height")]);
obj.axes = uiaxes(obj.figure, 'Position', [obj.x_position, obj.y_position,...
obj.image_dimensions("image_width"), obj.image_dimensions("image_height")]);
axis(obj.axes, 'image');
obj.axes.XAxis.TickLabels = {};
obj.axes.YAxis.TickLabels = {};
Expand Down Expand Up @@ -291,18 +295,22 @@ function addCallback(obj, x)
end

function obj = embiggenMatrix(obj, varargin)
% Enlarges data points of matrix for easier viewing. Also adds the network colorbars to the left axis and bottom axis.
% Enlarges data points of matrix for easier viewing.
% Also adds the network colorbars to the left axis and bottom axis.
import nla.gfx.colorChunk nla.gfx.MatrixType nla.gfx.drawLine

% If there are no inputs (like initial rendering) then we use defaults
% If there were inputs, that means we're scaling the colorbar.
if isempty(varargin)
initial_render = true; % Controls whether or not to add the bars on the side and bottom
upper_value = obj.upper_limit;
lower_value = obj.lower_limit;
else
initial_render = false;
upper_value = str2double(varargin{2});
lower_value = str2double(varargin{1});
end

number_of_networks = obj.number_networks;
dimensions = obj.image_dimensions;
network_matrix = obj.network_matrix;
Expand All @@ -324,8 +332,10 @@ function addCallback(obj, x)
chunk_height = numel(network_indexes) * obj.elementSize();

% Left side of matrix color bars
obj.drawLeftLinesOnLabels(position_y, chunk_height, dimensions, network);

if isequal(initial_render, true)
obj.drawLeftLinesOnLabels(position_y, chunk_height, dimensions, network);
end

position_x = dimensions("label_size") + dimensions("offset_x") + 3;
starting_x = position_x;
maximum_x = number_of_networks;
Expand All @@ -349,45 +359,47 @@ function addCallback(obj, x)
% Apply colors to chunks
obj.applyColorToData(position_x, position_y, chunk_height, chunk_width, chunk_color);

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

if ~isequal(obj.network_clicked_callback, false)
obj.network_dimensions(x, network, :) = [position_x, position_x + chunk_width - 1,...
position_y, position_y + chunk_height - 1];
end
% Add callbacks to all the squares
obj.addCallback(drawLine(obj.axes, [position_x - 1, position_x - 1],...
[position_y, position_y + chunk_height + 1]));
obj.addCallback(drawLine(obj.axes, [position_x - 2, position_x + chunk_width - 1],...
[position_y + chunk_height, position_y + chunk_height]));

if x == maximum_x && obj.matrix_type == MatrixType.TRIMATRIX && ~isequal(network_matrix, false)
obj.addCallback(drawLine(obj.axes, [position_x + chunk_width, position_x + chunk_width],...
[position_y - 1, position_y + chunk_height + 1]));
obj.addCallback(drawLine(obj.axes, [position_x - 2, position_x + chunk_width],...
[position_y - 1, position_y - 1]));
end
if isequal(initial_render, true)
% plot signifance marker
if ~isequal(obj.marked_networks, false) && isequal(obj.marked_networks(network, x), true)
obj.plotSignificanceMark(chunk_width, chunk_height, position_x, position_y);
end

if ~isequal(obj.network_clicked_callback, false)
obj.network_dimensions(x, network, :) = [position_x, position_x + chunk_width - 1,...
position_y, position_y + chunk_height - 1];
end
% Add callbacks to all the squares
obj.addCallback(drawLine(obj.axes, [position_x - 1, position_x - 1],...
[position_y, position_y + chunk_height + 1]));
obj.addCallback(drawLine(obj.axes, [position_x - 2, position_x + chunk_width - 1],...
[position_y + chunk_height, position_y + chunk_height]));

if x == maximum_x && obj.matrix_type == MatrixType.TRIMATRIX && ~isequal(network_matrix, false)
obj.addCallback(drawLine(obj.axes, [position_x + chunk_width, position_x + chunk_width],...
[position_y - 1, position_y + chunk_height + 1]));
obj.addCallback(drawLine(obj.axes, [position_x - 2, position_x + chunk_width],...
[position_y - 1, position_y - 1]));
end

% Is this the last network of a TriMatrix. Then we're done and need to add the bottom
if network == number_of_networks
top = position_y + chunk_height;
bottom = position_y + chunk_height + dimensions("label_size");
left = position_x;
right = position_x + chunk_width;
% Is this the last network of a TriMatrix. Then we're done and need to add the bottom
if network == number_of_networks
top = position_y + chunk_height;
bottom = position_y + chunk_height + dimensions("label_size");
left = position_x;
right = position_x + chunk_width;

obj.image_display.CData(top:bottom, left:right, :) = colorChunk(obj.networks(x).color,...
dimensions("label_size") + 1, chunk_width + 1);
obj.drawBottomLabels(chunk_width, chunk_height, position_x, position_y, x);
obj.image_display.CData(top:bottom, left:right, :) = colorChunk(obj.networks(x).color,...
dimensions("label_size") + 1, chunk_width + 1);
obj.drawBottomLabels(chunk_width, chunk_height, position_x, position_y, x);
end
end
position_x = position_x + chunk_width + 1;
end
position_y = position_y + chunk_height + 1;
end

if obj.matrix_type == MatrixType.TRIMATRIX && ~network_matrix
if obj.matrix_type == MatrixType.TRIMATRIX && ~network_matrix && initial_render
drawLine(obj.axes, [starting_x - 1, position_x - 1],...
[starting_y - 3 + obj.elementSize(), position_y - 2], 'w');
drawLine(obj.axes, [starting_x - 2, position_x - 1],...
Expand All @@ -403,7 +415,8 @@ function drawLeftLinesOnLabels(obj, position_y, chunk_height, dimensions, networ
bottom = position_y + chunk_height;
left = dimensions("offset_x") + 2;
right = dimensions("offset_x") + dimensions("label_size") + 1;
obj.image_display.CData(top:bottom, left:right+1, :) = colorChunk(obj.networks(network).color, chunk_height + 1, dimensions("label_size") + 1);
obj.image_display.CData(top:bottom, left:right+1, :) = colorChunk(obj.networks(network).color,...
chunk_height + 1, dimensions("label_size") + 1);

drawLine(obj.axes, [left - 1, right], [top - 1, top - 1]);
drawLine(obj.axes, [left - 1, right], [bottom, bottom]);
Expand Down Expand Up @@ -432,7 +445,8 @@ function plotSignificanceMark(obj, chunk_width, chunk_height, position_x, positi
left = position_x;
right = position_x + chunk_width;

obj.image_display.CData(top:bottom, left:right, :) = colorChunk(obj.networks(x_location).color, dimensions("label_size") + 1, chunk_width + 1);
obj.image_display.CData(top:bottom, left:right, :) = colorChunk(obj.networks(x_location).color,...
dimensions("label_size") + 1, chunk_width + 1);

obj.addCallback(drawLine(obj.axes, [left - 1, left - 1], [top, bottom]));
obj.addCallback(drawLine(obj.axes, [right, right], [top, bottom]));
Expand Down Expand Up @@ -470,9 +484,11 @@ function createLegend(obj)
display_legend.Units = 'pixels';
display_legend_width = display_legend.Position(3);
display_legend_height = display_legend.Position(4);
display_legend.Position = [obj.x_position + dimensions("plot_width") - display_legend_width - dimensions("offset_x") - obj.legend_offset,...
display_legend.Position = [...
obj.x_position + dimensions("plot_width") - display_legend_width - dimensions("offset_x") - obj.legend_offset,...
obj.y_position + dimensions("plot_height") - display_legend_height - dimensions("offset_y"),...
display_legend_width, display_legend_height];
display_legend_width, display_legend_height...
];
end

function createColorbar(obj, varargin)
Expand Down Expand Up @@ -525,27 +541,90 @@ function createColorbar(obj, varargin)
obj.color_bar.Title.FontSize = 7;

% Enables callback for clicking on colorbar to scale data
set(obj.color_bar, 'ButtonDownFcn', @changeColorLimits)
set(obj.color_bar, 'ButtonDownFcn', @obj.openModal)

caxis(obj.axes, [0, 1]);
end

function openModal(obj, source, ~)
% Callback for clicking on the colorbar.
function changeColorLimits(~, ~)
prompt = {"Enter Lower Limit: ", "Enter Upper Limit: "};
upper_limit_inner = obj.color_bar.TickLabels(end);
lower_limit_inner = obj.color_bar.TickLabels(1);
current_limits = {lower_limit_inner{1}, upper_limit_inner{1}};
new_limits = inputdlg(prompt, "Colorbar Limits", 1, current_limits);
% If "cancel" is pressed or both values deleted use defaults
if isempty(new_limits) || isempty(new_limits{1}) || isempty(new_limits{2})
obj.embiggenMatrix();
obj.createColorbar();
else
obj.embiggenMatrix(new_limits{1}, new_limits{2});
obj.createColorbar(new_limits{1}, new_limits{2});
end
% This opens a modal with the upper and lower bounds along with a radio selector between linear and
% log. This only works for a "regular" log scale, not the -log10 scale. Still working on that one
import nla.gfx.ProbPlotMethod

% source is the colorbar, not the figure
d = figure('WindowStyle', 'normal', "Units", "pixels", 'Position', [source.Position(1), source.Position(2),...
source.Position(3) * 15, source.Position(4) / 2]);
% These are the boxes that are the upper and lower end of the scale
upper_limit_box = uicontrol('Style', 'edit', "Units", "pixels", 'Position', [90, 130, 100, 30], "String",...
obj.upper_limit);
upper_limit_box.Position(4) = upper_limit_box.FontSize * 2;
lower_limit_box = uicontrol('Style', 'edit', "Units", "pixels", 'Position', [90, 100, 100, 30], "String",...
obj.lower_limit);
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)]);

% These are the buttons that make the scale log or linear
scaleBaseButtons = uibuttongroup(d, "Units", "pixels", "Position", [10, 60, 210, 30]);
linear_button = uicontrol(scaleBaseButtons, "Style", "radiobutton", "String", "Linear", "Units", "pixels",...
"Position", [10, 5, 60, 20]);
log_button = uicontrol(scaleBaseButtons, "Style", "radiobutton", "String", "Log", "Units", "pixels",...
"Position", [80, 5, 60, 20]);
neg_log_button = uicontrol(scaleBaseButtons, "Style", "radiobutton", "String", "-Log10", "Units", "pixels",...
"Position", [130, 5, 80, 20]);
% Here we're setting the initial setting for the linear or log button
if obj.plot_scale == ProbPlotMethod.DEFAULT || obj.plot_scale == ProbPlotMethod.STATISTIC
selected_value = linear_button;
elseif obj.plot_scale == ProbPlotMethod.LOG || obj.plot_scale == ProbPlotMethod.LOG_STATISTIC
selected_value = log_button;
else
selected_value = neg_log_button;
end
scaleBaseButtons.SelectedObject = selected_value;

apply_button_position = [10, 10, 100, 30];
apply_button = uicontrol('String', 'Apply',...
'Callback', {@obj.applyScale, upper_limit_box, lower_limit_box, scaleBaseButtons},...
"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(d), "Units", "pixels", 'Position',...
close_button_position);
end

function applyScale(obj, ~, ~, upper_limit_box, lower_limit_box, button_group)
% This callback gets the colormap/scale and then applies the new bounds to the data.
% Only works with APPLY button, will not work with only CLOSE

import nla.net.result.NetworkResultPlotParameter nla.gfx.ProbPlotMethod

button_group_value = get(get(button_group, "SelectedObject"), "String");

if ismember(obj.plot_scale, [ProbPlotMethod.NEG_LOG_10, ProbPlotMethod.NEG_LOG_STATISTIC]) &&...
ismember(button_group_value, ["Linear", "Log"])
obj.matrix.v = 10.^(-obj.matrix.v);
elseif ~ismember(obj.plot_scale, [ProbPlotMethod.NEG_LOG_10, ProbPlotMethod.NEG_LOG_STATISTIC]) &&...
~ismember(button_group_value, ["Linear", "Log"])
obj.matrix.v = -log10(obj.matrix.v);
end

discrete_colors = NetworkResultPlotParameter().default_discrete_colors;
if button_group_value == "Linear"
obj.color_map = NetworkResultPlotParameter.getColormap(discrete_colors, get(upper_limit_box, "String"));
obj.plot_scale = ProbPlotMethod.DEFAULT;
elseif button_group_value == "Log"
obj.color_map = NetworkResultPlotParameter.getLogColormap(discrete_colors, obj.matrix, get(upper_limit_box, "String"));
obj.plot_scale = ProbPlotMethod.LOG;
else
obj.color_map = parula(discrete_colors);
obj.plot_scale = ProbPlotMethod.NEG_LOG_10;
end
obj.embiggenMatrix(get(lower_limit_box, "String"), get(upper_limit_box, "String"));
obj.createColorbar(get(lower_limit_box, "String"), get(upper_limit_box, "String"));
end

function chunk_color = getChunkColor(obj, chunk_raw, upper_value, lower_value)
Expand Down
2 changes: 1 addition & 1 deletion +nla/+gfx/ProbPlotMethod.m
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
classdef ProbPlotMethod
enumeration
DEFAULT, LOG, NEG_LOG_10, STATISTIC
DEFAULT, LOG, NEG_LOG_10, STATISITC, LOG_STATISTIC, NEG_LOG_STATISTIC
end
end
3 changes: 2 additions & 1 deletion +nla/+net/+result/+plot/NoPermutationPlotter.m
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,12 @@
plot_label = parameters.name_label;
significance_plot = parameters.significance_plot;
clickCallback = parameters.callback;
plot_scale = parameters.plot_scale;

matrix_plot = nla.gfx.plots.MatrixPlot(plot_figure, plot_label, statistic_matrix, obj.network_atlas.nets,...
nla.gfx.FigSize.SMALL, 'x_position', x_coordinate, 'y_position', y_coordinate, 'lower_limit', 0,...
'upper_limit', p_value_max, 'color_map', color_map, 'network_clicked_callback', clickCallback,...
'marked_networks', significance_plot);
'marked_networks', significance_plot, 'plot_scale', plot_scale);
matrix_plot.displayImage();
w = matrix_plot.image_dimensions("image_width");
h = matrix_plot.image_dimensions("image_height");
Expand Down
Loading