How to color a line based on error range
2 views (last 30 days)
Show older comments
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
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.
Answers (1)
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.
See Also
Categories
Find more on Line Plots in Help Center and File Exchange
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!