Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Matlab: Indicate on a plot when data is off the plot?

Tags:

plot

matlab

Is there a way to have a mark on a plot axis for any data points off the current plot in Matlab? It is great if the method works with zoom and pan, but I can live without it.

I have several data sets that I am plotting using subplots. Each plot contains 20 data points, similar to marking where darts landed on a dart board. For most data sets, these plots are within a standard range, ie the size of the dart board, so I am using this standard for the axis range of each plot to make the subplots easily visually comparable. However, a few data sets have an outlier that is outside this standard range (typically way outside). I do not want to change the axis to show the outlier, but I want the user to be aware that there is 1 or more data points off the plot, and preferably in which direction they are off.

I thought a bit about trying to use the axis markers (set(gca, 'Ytick', xLowerLimit: markSpacing: xUpperLimit)) and adding an extra marker in a different color to indicate the location of an outlier, but I couldn't see how to do this without disrupting the regular markers and in a automated way that could allow for multiple outlier marks.

like image 743
Ayshaya Avatar asked Jan 29 '26 02:01

Ayshaya


2 Answers

One approach is to see if there is any data that exceed your Y Axis limit and then place some text somewhere to notify the user. Options include text (puts text on axis) or uicontrol (puts text somewhere in figure window).

Here is an example using uicontrol:

% Set up figure window and axes
h.f = figure;
h.ax = axes('Units', 'Normalized', 'Position', [0.13 0.2 0.75 0.75]);

% Plot some sample data and window our axes to replicate the question
x = 1:10;
y = [1:9 20];

xmin = 0; xmax = 10;
ymin = 0; ymax = 10;
plot(h.ax, x, y);
axis(h.ax, [xmin xmax ymin ymax]);

% Generate logical matrix to find if any y data is beyond our axis limit
ymask = y > ymax;

if any(ymask) % Loop triggers if any y value is greater than ymax
    str = sprintf('There are %u data points greater than current y axis limit', sum(ymask));
    uicontrol('Parent', h.f, ...
              'Style', 'text', ...
              'Units', 'Normalized', ...
              'Position', [0.01 0.01 0.9 0.05], ...
              'String', str ...
              );
end

Which generates the following (annotations added manually):

yay

This can be extended to other directions with some simple copy + paste and tweaks.

like image 179
sco1 Avatar answered Jan 31 '26 07:01

sco1


Edit: see bottom for improved method using callbacks.

You can find data points exceeding the axes limits and draw them on the limits, using different symbols:

A = randn(20, 2);

x_range = [-1.5, 1.5];
y_range = [-1.5, 1.5];

figure(1);
clf;
ah = axes;
plot(ah, A(:,1), A(:,2), 'o')
hold on
set(ah, 'XLim', x_range, 'YLim', y_range)

x_lt = A(:,1) < x_range(1);
x_gt = A(:,1) > x_range(2);
y_lt = A(:,2) < y_range(1);
y_gt = A(:,2) > y_range(2);

A_out = A;
A_out(x_lt, 1) = x_range(1);
A_out(x_gt, 1) = x_range(2);
A_out(y_lt, 2) = y_range(1);
A_out(y_gt, 2) = y_range(2);
A_out = A_out(x_lt | x_gt | y_lt | y_gt, :);
plot(ah, A_out(:,1), A_out(:,2), 'rx')

This produces a plot like this:

Example plot with outliers

Edit: add callbacks

If you really want to go fancy, you can add callbacks so that outliers are automatically drawn (and removed) when the figure is zoomed. Adding the same functionality for panning is left as an exercise to the reader ;)

mark_outliers.m:

function mark_outliers(fig, ax)
ah = ax.Axes;
lobj = findobj(ah, 'Type', 'Line');
x_range = ah.XLim;
y_range = ah.YLim;
ah.NextPlot = 'add';
for i_l = 1:numel(lobj)
    xd = lobj(i_l).XData;
    yd = lobj(i_l).YData;
    x_lt = xd < x_range(1);
    x_gt = xd > x_range(2);
    y_lt = yd < y_range(1);
    y_gt = yd > y_range(2);
    outliers = x_lt | x_gt | y_lt | y_gt;
    if any(outliers)
        xd_out = xd;
        xd_out(x_lt) = x_range(1);
        xd_out(x_gt) = x_range(2);
        yd_out = yd;
        yd_out(y_lt) = y_range(1);
        yd_out(y_gt) = y_range(2);
        xd_out = xd_out(outliers);
        yd_out = yd_out(outliers);

        plot(ah, xd_out, yd_out, 'xr', 'Tag', 'Outliers')
    end
end

delete_outliers.m:

function delete_outliers(fig, ah)
    ah = ah.Axes;
    delete(findobj(ah, 'Tag', 'Outliers'));

example.m:

A = randn(20, 2);

fh = figure(1);
clf;
ah = axes;
plot(ah, A(:,1), A(:,2), 'o')

h = zoom(fh);
h.ActionPreCallback=@delete_outliers;
h.ActionPostCallback=@mark_outliers;
like image 30
zeeMonkeez Avatar answered Jan 31 '26 08:01

zeeMonkeez



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!