MATLAB Answers

Plotting different colored line based on condition(s)

36 views (last 30 days)
Hello: I am attempting to plot a line that changes colors (between red and green) based upon the value of the data. For example, if I have x=1:1:5 and corresponding y=[-2,-1,1,2,3], I would like the plot to have a red line when y is negative and a green line when y is positive and have a corresponding legend to denote this. P.S. my actual data series is much longer than (5) values so a looping code would be preferable.

Accepted Answer

Chad Greene
Chad Greene on 6 Oct 2020
Edited: Chad Greene on 6 Oct 2020
What if you create two lines and plot them separately?
x = 0:1000;
y = sind(x);
% duplicate:
y_red = y;
y_red(y>0) = NaN;
y_green = y;
y_green(y<0) = NaN;
hold on
Adam Danz
Adam Danz on 6 Oct 2020
This is the best method when the x values are already known at y=0. It's simple, effective, and quick. But if the x coordinates are not known when y=0, you'll need to compute them and insert them into the (x,y) vectors.
For example, try approach solution when x = 22:45:1080.

Sign in to comment.

More Answers (1)

Adam Danz
Adam Danz on 6 Oct 2020
Edited: Adam Danz on 6 Oct 2020
A line object can only have 1 color. To change the color of values above and below y=0 you have to break up your line into segments. This is relatively easy if you already have y-coordinates at (or very close to) zero and can be solved by simple logical indexing.
However if line segments pass through y=0 you must compute the x-coordinates where y equals 0 and insert those coordinates into your (x,y) vectors.
Here's a demo that steps through that process.
% Define coarse (x,y) coordinates that pass through y=0
y = [y,fliplr(y),y];
% Plot the original data
% Get the index of each coordinate just prior to passing y=0 (startSegIdx)
signDiff = [0,diff(sign(y(:)'))];
startSegIdx = unique([find(signDiff(:)'==2)-1, find(signDiff(:)'==-2)-1])
startSegIdx = 1×3
2 8 12
% For each segment that passes through y=0, compute equation
% of the line and solve for y=0
x0 = nan(size(startSegIdx));
for i = 1:numel(startSegIdx)
coeffs = polyfit(x(startSegIdx(i)+[0,1]), y(startSegIdx(i)+[0,1]), 1);
x0(i) = -coeffs(2)/coeffs(1);
% (x0,y0) are the y== crossing points. Add those points to the plot
% to check for accuracy
hold on
plot(x0,zeros(size(x0)),'m*','MarkerSize', 12,'LineWidth',2)
% Insert the new (x0,y0) coordinates in the correct incides of (x,y)
repNum = ones(size(x));
repNum(startSegIdx) = 2;
xNew = repelem(x(:).',1,repNum(:)');
xNew(startSegIdx + (1:numel(startSegIdx))) = x0;
yNew = repelem(y(:).',1,repNum(:)');
yNew(startSegIdx + (1:numel(startSegIdx))) = 0;
% Plot the new line to make sure it matches the old one, plus the 0-crossings
hold on
plot(x0,zeros(size(x0)),'m*','MarkerSize', 12,'LineWidth',2)
plot(xNew, yNew, 'r:o', 'LineWidth', 1, 'MarkerSize', 16)
% Break up the (xNew,yNew) line into segments below/above y=0
% There will be 1 segment for each time it crosses y=0
% 1. Duplicate values at x=0
segmentSub = unique(find(sign(yNew(:)')==0));
repNum2 = ones(size(xNew));
repNum2(segmentSub) = 2;
xSeg = repelem(xNew, 1, repNum2);
ySeg = repelem(yNew, 1, repNum2);
% create a grouping variable for each element of (xSeg, ySeg) that identifies its segment.
segmentSub2 = [segmentSub + (0:numel(segmentSub)-1), numel(xSeg)];
group = repelem(1:numel(segmentSub2),diff([0,segmentSub2]));
% Plot the line segments
hold on % important
h = splitapply(@(x,y)plot(x,y,'-o','LineWidth',1),xSeg,ySeg,group);
% Color segment based on the sign of y values
isPositive = arrayfun(@(h)any(h.YData > 0),h);
set(h(isPositive), 'Color', 'g')
set(h(~isPositive), 'Color', 'r')
% add ref line

Community Treasure Hunt

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

Start Hunting!

Translated by