Is it possible to plot a curve with changing colours under a single plot?

A would like to plot a curve with different colour line segments, and I need to do it under a single plot handle. Is it possible to do with the standard plot function, or I need something else?

 Accepted Answer

Arguably, this is something the line function would allow you to do. But line allows you to specify only a single color for an entire line. plot is also unable to do as you wish.
You could, if you wanted, plot each segment of some line using different colors. For example,
n = 100;
x = linspace(0,1,n);
y = exp(x);
C = jet(n-1);
C = mat2cell(C,ones(n-1,1),3);
H = line([x(1:n-1);x(2:n)],[y(1:n-1);y(2:n)]);
[H.Color] = deal(C{:});
Yes, this is a bit tricky, and it requires that you understand how comma separated lists work, and how to use them. Again, I'd have argued plot or line should have the capability to do it directly, certainly so for line. I did it using line, but it was a bit of a kluge in my eyes. Effectively, there are 99 distinct segments there, each of which has its own specified color.

8 Comments

Thank you very much, thats what I am looking for!
Sorry, there is problem with this! In case for thick lines, at the braking points (where there is an angle between segments) there are gaps! That is why plot is better. I think, the only solution for this is to do a for cycle and plot two adjacent segments with the plot function at the same time with the appropriate color. But somehow I want to hadle the whole curve as one plot object. Are there any solution?
Wait. You did not say the lines had to be THICK lines. Sigh. I hate moving targets.
Imagine the lines were very short, and very thick. So much so that each line ends up being not a relatively very long thin rectangle, but a square. Got it? Now plot many of these squared line segments, one after another. Now, imagine a curved sequence of these square blocks.
The result will be blank places, where the squares don't match up, where they don't lie with nice parallel sides. And there is very little to be done for this problem, because in order to plot a CURVED and THICK line that changes color, each segment needs to be different blocks.
Could it be solved using multiple patches with trapezoidal shapes? Well, yes, if you want a significantly thick line. But then each such patch needs to be generated separately.
Can you use plot? Sorry but no. Plot CANNOT handle such a line with varying color. Line cannot do so either. You could send in a feature request into technical support, so that possibly, one day in the future they might add it to MATLAB, probably as a capability of the line tool. (Answers is not techical support.)
Finally, the idea of using plot to plot adjacent segments also does not really work, for exactly the same reason. If you make the lines thick, so that now the aspect ratio of the segments is sufficient that you can see the ends of the segments and where they meet up, it must fail, and for exactly the same reason.
Or possibly you meant that you could use the idea I showed in my answer to draw two color varying lines but offset one from the other. This will work, until it completely fails. For example, make the curved line a complete circle, or ANY curved line at all. You cannot easily offset a curved line by some constant amount in any fixed direction. For a circle, you could draw two circles, of slightly different radii.
Sorry. There are limits to what you can do. And if you need to make the lines as thick lines, then you will need to accept the existence of flaws in what you will see.
Can you show an example of the behavior you're getting? I don't see any gaps where there are steps.
n = 10;
x = rand(1,n);
y = rand(1,n);
C = jet(n-1);
C = mat2cell(C,ones(n-1,1),3);
H = line([x(1:n-1);x(2:n)],[y(1:n-1);y(2:n)]);
[H.Color] = deal(C{:});
As far as plotting a bunch of individually-colored adjacent segments, that's what this does; it's just a very compact way of doing it. Both plot() and line() create line primitives, but plot() is a higher-level tool that has some extra conveniences.
As far as I see: 'plot' can handle thick lines, but line cannot handle them, however 'plot' cannot handle changing colors, but 'line' can handle it. So the only way to do this, is using plot with pair of segments and do a for cycle along the trajectory. My problem is, how to handle the whole curve as one plot object in a GUI, because I don't want to assign a name to each segment, and I need to work with later, for example update the plot, change thickness, change layer order, etc.
Oh. I missed the point about thick lines. You could do something like you suggest with adjacent pairs, but you'll still get weird overlapping even though there aren't gaps. You can change the mitering method, but not the end caps.
n = 10;
x = rand(1,n);
y = rand(1,n);
C = jet(n-2);
C = mat2cell(C,ones(n-2,1),3);
xx = [x(1:n-2); x(2:n-1); x(3:n)];
yy = [y(1:n-2); y(2:n-1); y(3:n)];
H = line(xx,yy,'linewidth',7);
[H.Color] = deal(C{:});
This also means that the last color is applied to two visible segments.
... Given how bad that looks, you could always consider using a pseudoline generated via scatter(). It's still not going to give you crisp symmetric miters, but I think it looks marginally better.
nverts = 10;
x = rand(1,nverts);
y = rand(1,nverts);
% oversample everything by some factor
ptsperseg = 1000;
CT = jet(nverts-1);
CT = repelem(CT,ptsperseg,1);
pf = linspace(1,nverts,(nverts-1)*ptsperseg);
xf = interp1(x,pf,'linear');
yf = interp1(y,pf,'linear');
scatter(xf,yf,20,CT,'filled')
That also fixes the issues with the last two segments being colored the same.

Sign in to comment.

More Answers (1)

As others have noted, you cannot use the plot or line commands to create a multi-color line in MATLAB today, but this is possible in MATLAB, without using multiple line objects or even more scatter points.
The best way to plot a single multi-color line in MATLAB today is using the patch command. In fact, there is even an example in the doc that shows how to do it.
Patches are ordinarily used to draw filled regions, but if you insert a NaN into the vertices, then patch can be used to draw lines instead. And, multi-color lines in a Patch object is fully supported and documented, by setting the EdgeColor to interp and then setting either the CData or FaceVertexCData.
Here is an amended version of the example from the doc that includes wide lines and adjusting the LineJoin to get a different connection between individual segments:
figure
x = linspace(1,10,15);
y = sin(x);
y(end) = NaN;
c = y;
patch(x,y,c,'EdgeColor','interp','LineWidth',5,'LineJoin','round');
And, to emphasize how LineJoin works in this case, here is another example:
figure
nverts = 10;
x = rand(nverts,1);
y = rand(nverts,1);
c = turbo(nverts+1);
v = [x y; NaN NaN];
f = 1:nverts+1;
patch('Vertices',v, ...
'Faces',f, ...
'FaceVertexCData',c, ...
'EdgeColor','interp', ...
'LineWidth',10, ...
'LineJoin','round');

1 Comment

For some reason I can't upvote this. Let this comment be my upvote!

Sign in to comment.

Categories

Asked:

on 28 May 2023

Commented:

DGM
on 29 May 2023

Community Treasure Hunt

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

Start Hunting!