How to color a line based on error range

8 views (last 30 days)
John
John on 4 Jan 2016
Edited: John on 5 Jan 2016
Original question: I'm trying to color a line based on the error, with levels set at 10% and 25% of the error range. The attached code predicts a response, and plots the response and prediction, along with the difference between the response and prediction, and the cumulative probability of the difference. The problem is most visible in the second plot. The colors should be in bands, red > 25%, blue > 10%, and green < 10% of error range. How can the code be corrected to show the proper colors?
Revised question:
The code below generates a figure with three plots. The top plot shows a black line for data, and a multicolor line for a 3-sec forecast of the data. The middle plot shows the error between data and forecast (data-forecast). The bottom plot shows the cumulative probability distribution of the error. What I would like to do is color the lines associated with the forecast based on the level of error. In particular, if the abs(error) is less than 10% of the error range, then the line should be green. If the abs(error) is between 10% and 25% of the error range, then the line should be blue (I have trouble seeing yellow). If the abs(error) is above 25%, then the line should be red. So, in the top plot, the forecast line should be green, blue, and red, indicating where the low is low, medium, or high. Likewise, the middle plot the line should be colored green, blue, and red, and should correspond directly with the top lines, and also the colors should appear in horizontal bands since the y-axis is error. That is, when the error (or y-axis value) is less than 10%, the line should be green. When the error is between 10% and 25%, the line should be yellow. And when the error is above 25%, the line should be red. The bottom figure is actually correct, and does show the cumulative probability colored based on error range (or the x-axis), and shows up as vertical bands.
The reason the code doesn't work is that when the line is a function of time, for the top and middle plots, then addition points need to added when the color changes. The problem now is the color lines extend into the next bands. So, in the top plot you can have a higher color appear less than a lower color, for example, at time 0.595, the blue line changes to a green line at a higher value of error, or the green line error is higher than the blue, which should not occur.
So the question is how to interpolate the forecast line (top plot) and the error line (middle plot) to add values at the times when the colors change (10% and 25% of the error range).
function line_color
%%Question about plot colors
close all; clc; clear;
load iddata9 z9
Ts = z9.Ts;
y1 = cumsum(z9.y);
model = ar(y1, 6, 'ls', 'Ts', Ts, 'IntegrateNoise', true);
[yc1,fit,x0] = compare(y1,model,6);
t1=Ts*((1:length(y1))-1);
yel_pcnt = 10;
red_pcnt = 25;
[t, y, yc, err_dist, cum_err_count, time_indx, err_time, hist_indx] = plot_3_color_line(t1,y1,yc1,yel_pcnt,red_pcnt);
c_color = {'g','b','r'};
figure; nrows = 3; ncols = 1; iplot = 0;
iplot = iplot+1; subplot(nrows,ncols,iplot);
for ic=1:3
x_indx = time_indx{ic}.indx;
x_bad_indx = find(isnan(x_indx));
x_indx(x_bad_indx)=1;
x_data = t(x_indx);
x_data(x_bad_indx) = nan;
y_data_2 = yc(x_indx);
y_data_2(x_bad_indx) = nan;
if (ic == 1)
hp_time_data(1)=plot(t, y, ['k-']);
hold all;
end
hp_time_data(1+ic)=plot(x_data, y_data_2, [c_color{ic},'--'],'linewidth',1);
end
xlabel('time'); ylabel('Response');
legend(hp_time_data, ...
sprintf('Data'), ...
sprintf('Fcst < %3.0f%%',yel_pcnt), ...
sprintf('Fcst < %3.0f%%',red_pcnt), ...
sprintf('Fcst > %3.0f%%',red_pcnt), ...
'location','best');
iplot = iplot+1; subplot(nrows,ncols,iplot);
for ic=1:3
x_indx = time_indx{ic}.indx;
x_bad_indx = find(isnan(x_indx));
x_indx(x_bad_indx)=1;
x_data = t(x_indx);
x_data(x_bad_indx) = nan;
y_data = err_time(x_indx);
y_data(x_bad_indx) = nan;
hp_time_err(ic)=plot(x_data, y_data, c_color{ic},'linewidth',1);
hold all;
end
xlabel('time'); ylabel('Error (Data-Forecast)');
legend(hp_time_err, ...
sprintf('< %3.0f%%range',yel_pcnt), ...
sprintf('< %3.0f%%',red_pcnt), ...
sprintf('> %3.0f%%',red_pcnt), ...
'location','northwest');
iplot = iplot+1; subplot(nrows,ncols,iplot);
for ic=1:3
x_indx = hist_indx{ic}.indx;
x_bad_indx = find(isnan(x_indx));
x_indx(x_bad_indx)=1;
x_data = err_dist(x_indx);
x_data(x_bad_indx) = nan;
y_data = cum_err_count(x_indx)*100;
y_data(x_bad_indx) = nan;
hp_cumm(ic)=plot(x_data, y_data, c_color{ic},'linewidth',1);
hold all;
end
xlabel(sprintf('Data - Fcst'));
ylabel('Cummulative Percent');
legend(hp_cumm, ...
sprintf('< %3.0f%%range',yel_pcnt), ...
sprintf('< %3.0f%%',red_pcnt), ...
sprintf('> %3.0f%%',red_pcnt), ...
'location','northwest');
end
function [t, y, y_est, err_dist, cum_err_count, time_indx, err_time, hist_indx, c_color] = plot_3_color_line(t,y,y_est,yel_pcnt,red_pcnt)
err_time = y-y_est;
[err_count,err_dist]=hist(err_time,100);
err_count = err_count/sum(err_count);
cum_err_count = cumsum(err_count);
rng_err = max(err_time) - min(err_time);
hist_indx{1}.indx = [];
hist_indx{2}.indx = [];
hist_indx{3}.indx = [];
indx_hist_red = abs(err_dist)>red_pcnt/100*rng_err;
i_yellow_hist = abs(err_dist)>yel_pcnt/100*rng_err & ~indx_hist_red;
i_green_hist = ~indx_hist_red & ~i_yellow_hist;
i_color_hist = indx_hist_red*3+i_yellow_hist*2+i_green_hist;
delta_color_hist = diff(i_color_hist);
indx_color_change_hist = find(delta_color_hist~=0);
if (indx_color_change_hist(1) > 1)
indx_color_change_hist = [1 indx_color_change_hist];
end
if (indx_color_change_hist(end) < length(indx_hist_red))
indx_color_change_hist = [indx_color_change_hist length(indx_hist_red)];
end
for ic = 1:(length(indx_color_change_hist)-1)
indx = indx_color_change_hist(ic):indx_color_change_hist(ic+1);
colIndx = i_color_hist(indx_color_change_hist(ic)+1);
if (isempty(hist_indx{colIndx}.indx))
hist_indx{colIndx}.indx = indx;
else
hist_indx{colIndx}.indx = [hist_indx{colIndx}.indx nan indx];
end
end
time_indx{1}.indx = [];
time_indx{2}.indx = [];
time_indx{3}.indx = [];
indx_time_red = abs(err_time)>red_pcnt/100*rng_err;
i_yellow_time = abs(err_time)>yel_pcnt/100*rng_err & ~indx_time_red;
i_green_time = ~indx_time_red & ~i_yellow_time;
i_color_time = indx_time_red*3+i_yellow_time*2+i_green_time;
delta_color_time = diff(i_color_time);
indx_color_change_time = find(delta_color_time~=0);
if (indx_color_change_time(1) > 1)
indx_color_change_time = [1; indx_color_change_time];
end
if (indx_color_change_time(end) < length(indx_time_red))
indx_color_change_time = [indx_color_change_time; length(indx_time_red)];
end
for ic = 1:(length(indx_color_change_time)-1)
indx = indx_color_change_time(ic):indx_color_change_time(ic+1);
colIndx = i_color_time(indx_color_change_time(ic)+1);
if (isempty(time_indx{colIndx}.indx))
time_indx{colIndx}.indx = indx;
else
time_indx{colIndx}.indx = [time_indx{colIndx}.indx nan indx];
end
end
end
  2 Comments
Walter Roberson
Walter Roberson on 4 Jan 2016
I do not follow what the various {ic} are for, but it looks to me as if you are encountering the difficulty that any one line or lineseries or chart line object can only be a single color.
John
John on 5 Jan 2016
I'm dividing the original line into segments of constant color. This works well for the bottom plot where the x-axis is error. But, when the x-axis is time (top two plots), then the line needs to have point added when the points cross the error boundaries. The error boundaries are +/- 10 and 25% of the error range. The {ic} correspond to the color for the error boundary, green for error < 10%, blue for error > 10% and less than 25%, and red for error > 25%. Percentage of the error range.

Sign in to comment.

Answers (1)

Joseph Cheng
Joseph Cheng on 5 Jan 2016
So.... after digging through your code (next time please include a picture of what you're dealing with and why you don't like it). From your description and what I'm assuming your second figure looks like, I propose that you're using the hist() and the resulting err_dist in your plot_3_color_line() incorrectly. I say this as the [err_count,err_dist] = hist() returns the bins of the histogram and not the individual errors associated to the y data index. such that if i go and insert
figure,bar(err_dist,err_count)
after your hist call you'll see that later when you're plotting
x_indx = time_indx{ic}.indx;
x_data = t(x_indx);
hp_time_err(ic)=plot(x_data, y_data, c_color{ic},'linewidth',1);
that the bands should correspond to the error centered on your line. with green at the center then blue then red at the ends of the line.
  1 Comment
John
John on 5 Jan 2016
Sorry about not making the question clearer. I'll modify the question above. But, essentially, the top figure shows the comparison between forecast and data. The middle figure shows the error between data and forecast (data-forecast). Both the top and middle figure have time on the x axis. The bottom figures shows the cumulative probability of error, and the x axis is the error value. The forecast line in the top figure, and the error and probability lines in the middle and bottom figures are colored based on the value of the error. The coloring is green for abs(error)<10% of error range, and blue for 10%<abs(error)<25% and red for abs(error)>25%. The problem is in the top two figures, that are functions of time. The coloring in the middle figure should result in horizontal bands, since the y axis is the error, and the bands should be at 10% and 25% of the range. The reason it doesn't work is that the error as a function of time needs to have points added that correspond to the crossing of the color limits. The same problem with the forecast line in the first figure.

Sign in to comment.

Community Treasure Hunt

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

Start Hunting!