- If X and Y are both vectors, then they must have equal length. The plot function plots Y versus X.
- If X and Y are both matrices, then they must have equal size. The plot function plots columns of Y versus columns of X."

223 views (last 30 days)

Show older comments

Introduction

Recently I found that in some circumstances the function plot is extremely slow, and I needed to find a solution to this problem. This post contains a description of this problem, and a possible solution which I found.

More specifically, consider the following code:

N = 1E6;

x = rand(N,1) ; y = rand(N,1);

figure

subplot(1, 3, 1);

tic ; hndl = plot(x, y, 'k--') ; axis square ; toc

numel(hndl)

subplot(1, 3, 2);

x_ = [ x(1:end-1) x(2:end) ]';

y_ = [ y(1:end-1) y(2:end) ]';

tic ; hndl = plot(x_, y_, 'k--') ; axis square ; toc

numel(hndl)

This program plots exactly the same image, with exactly the same number of lines, but the computational time are astonishingly different! On my PC I got the following result:

Elapsed time is 0.003680 seconds.

ans =

1

Elapsed time is 313.721635 seconds.

ans =

999999

Possible explaination for this issue

This issue is by no way related with a problem with OpenGL, or the graphic card driver, or the operative system. The point is that plotting a single polygon composed of N line by using the function plot is extremely faster than plotting the same N lines independently. In fact, I believe that the problem is due to the fact that when multiple lines have to be plotted, Matlab must creates as many instances of graphical objects (in this case matlab.graphics.chart.primitive.Line). Of course, this is my personal opinion.

By the way, replacing the function plot by the function line, or increasing Java memory both doesn't improve the performances.

Solution

A possible way to mitigate this problem is to use the function patch instead of plot. In most cases, this will produce nearly identical outputs. For instance, we can complete the previous program with:

subplot(1, 3, 3);

x_ = [ x(1:end-1) x(2:end) ]';

y_ = [ y(1:end-1) y(2:end) ]';

tic ; hndl = patch(x_, y_, 'k') ; axis square ; box on ; toc

numel(hndl)

One observes that in this case a single handle of class matlab.graphics.primitive.Patch is instanciated. The computational time is still much higher than in the trivial case (plotting of a polygon, elaped time = 0.003680 seconds), but becomes acceptable:

Elapsed time is 0.688164 seconds.

ans =

1

Hereafter it is depicted the output of the program in the case N = 20. One observes that the three graphics are practically identical:

This workaround is acceptable when continuous lines have to be plotted. As long as it is required to have more styled lines, it is possible to play with the argument provided to the function patch, but the result will not be exactly the same. For instance, in order to obtain dashed lines one can se the property LineStyle:

hndl = patch(x_, y_, 'k', 'LineStyle', '--')

The output is not identical to the one obtained with plot, but it may be acceptable, depending on your requirements:

Conclusion

In some circumstances the function plot has very poor performances. This issue seems to be related to the number of instances of graphical handles which are created. A possible workaround, which produces identical or very similar outputs, is to replace the function plot with patch.

R. Scorretti

Steven Lord
on 5 Jun 2020

- If X and Y are both vectors, then they must have equal length. The plot function plots Y versus X.
- If X and Y are both matrices, then they must have equal size. The plot function plots columns of Y versus columns of X."

Let me show a smaller data set, N = 100.

>> N = 1e2;

>> x = rand(N,1) ; y = rand(N,1);

>> x_ = [ x(1:end-1) x(2:end) ]';

y_ = [ y(1:end-1) y(2:end) ]';

>> whos x x_ y y_

Name Size Bytes Class Attributes

x 100x1 800 double

x_ 2x99 1584 double

y 100x1 800 double

y_ 2x99 1584 double

Plotting x and y falls into the first case, since they're both vectors. You get one graphics object.

Plotting x_ and y_ falls into the second case, since they're both matrices. You get size(x_, 2)-1 (or writing it a different way, N-1) graphics objects.

If you want to plot the individual line segments visually but create only 1 graphics object instead of N-1, you can do this by adding NaN values.

>> x2 = [x_; NaN(1, N-1)];

>> x2 = x2(:);

>> y2 = [y_; NaN(1, N-1)];

>> y2 = y2(:);

Let's try this on some non-random data.

>> A = [1 3 5; 2 4 6; NaN(1, 3)];

>> A = A(:);

>> B = A;

>> h = plot(A, B);

>> numel(h) % 1

Visually there are three line segments. The points (2, 2) and (3, 3) aren't connected because there's a (NaN, NaN) inbetween. But h only has one element.

Ameer Hamza
on 5 Jun 2020

Edited: Ameer Hamza
on 5 Jun 2020

I am not sure what is the purpose of using second code is instead of the first when both create the same plots, however, if you want to use the second method, the following will be faster

subplot(1, 3, 2);

x_ = [ x(1:end-1) x(2:end) ]; % <== remove transpose

y_ = [ y(1:end-1) y(2:end) ]; % <== remove transpose

tic ; hndl = plot(x_, y_, 'k--') ; axis square ; toc

numel(hndl)

The reason for it being slow is that MATLAB needs to create multiple line objects (equal to number of columns in x_) in that case, which is a slow operation. In the first case, only a single line object is created.

Ameer Hamza
on 5 Jun 2020

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!