Apologies in advance for bringing a non-programming question to SO, but the powers-that-be have determined that all MATLAB-related questions belong here.
I've been doing some Kalman Filters and plotting state variable estimates to see how they converge over time. Now, I'd like to visually represent the covariance matrix, which is an indication of the uncertainty in the estimate. So I wrote a little function that colors a band around the estimate.
(Edit note: A prior version made the mistake of using 2*cov
for the width of each halfband, when it needs to be 2 standard deviations)
function [ls, regions] = plotuncertain( t, y, cov )
t = t(:);
y = y(:);
stdev = cov(:).^(1/2);
a = ones(size(t));
regions(1) = patch('XData', [t; t(end:-1:1)], ...
'YData', [y + 2*stdev; y(end:-1:1)], ...
'FaceVertexAlphaData', [0*a; a], ...
'FaceAlpha', 'interp', 'EdgeColor', 'none');
regions(2) = patch('XData', [t; t(end:-1:1)], ...
'YData', [y - 2*stdev; y(end:-1:1)], ...
'FaceVertexAlphaData', [0*a; a], ...
'FaceAlpha', 'interp', 'EdgeColor', 'none');
ls = line('XData', t, 'YData', y);
And it looks reasonable:
But I have two state variables with similar meaning that I'd like to plot concurrently on a single axis.
Uh-oh, the initial data for k_1 is obscured by the (top half of the) k_2 band. MATLAB didn't draw the lines and patches in the order I submitted them. And even if I manage to control the order they draw, alpha-blending is still less optimal than mixing the colors based on the probabilities.
Any ideas how to render both at the same time? Can I somehow take advantage of the fact that I'm using two distinct color planes for the two variables?
When plots are too complex, matlab starts to behave erratically just like here. I often try to apply a solution described here.
For your particular (and very nice) plot, I would modify the function by declaring an axes:
function [ax, ls, regions] = plotuncertain( t, y, cov )
ax = axes;
t = t(:);
y = y(:);
cov = cov(:);
a = ones(size(t));
regions(1) = patch('XData', [t; t(end:-1:1)], ...
'YData', [y + 2*cov; y(end:-1:1)], ...
'FaceVertexAlphaData', [0*a; a], ...
'FaceAlpha', 'interp', 'EdgeColor', 'none');
regions(2) = patch('XData', [t; t(end:-1:1)], ...
'YData', [y - 2*cov; y(end:-1:1)], ...
'FaceVertexAlphaData', [0*a; a], ...
'FaceAlpha', 'interp', 'EdgeColor', 'none');
ls = line('XData', t, 'YData', y);
and then call the function with:
[ax1, ls, regions] = plotuncertain( t, y, cov );
[ax2, ls, regions] = plotuncertain( t, y, cov );
set(ax2,'Visible','off');
linkaxes([ax1 ax2],'xy'); %or any (XLim,YLim) settings
This way, transparency in one axes is independent of the other.
EDIT
A way to better control the color blending is to convert each of the axes created in a dedicated figure into an image and then fuse them. One can use for example imfuse(im1,im2,'blend')
(image processing toolbox) or whatever function that mixes 2 images.
The way to extract an image from a figure is
F = getframe(gcf);
imwrite(F.cdata, 'image.png');
For sure, this solution is only suitable at the final step of a reporting process (I would definitively not use it for a scientific article - see the comments - but for spectacular presentations). It may also be more efficient to use an alternative software that better deals with transparency/OpenGL than Matlab does.
Although you suggest having attempted this, I found swapping the order of the patches made a large difference.
My version of your example, first without swapping:
t=[1:100];
y=t.^2;
cov=t.^2;
t2=[1:100];
y2=t2.^2.05;
cov2=t2.^2;
figure
t = t(:);
y = y(:);
cov = cov(:);
a = ones(size(t));
t2 = t2(:);
y2 = y2(:);
cov2 = cov2(:);
a = ones(size(t2));
regions(1) = patch('XData', [t; t(end:-1:1)], ...
'YData', [y + 2*cov; y(end:-1:1)], ...
'FaceVertexAlphaData', [0*a; a], ...
'FaceAlpha', 'interp', 'EdgeColor', 'none', 'FaceColor', 'r');
regions(2) = patch('XData', [t; t(end:-1:1)], ...
'YData', [y - 2*cov; y(end:-1:1)], ...
'FaceVertexAlphaData', [0*a; a], ...
'FaceAlpha', 'interp', 'EdgeColor', 'none', 'FaceColor', 'r');
ls = line('XData', t, 'YData', y,'Linewidth',1.5);
regions(3) = patch('XData', [t2; t2(end:-1:1)], ...
'YData', [y2 - 2*cov2; y2(end:-1:1)], ...
'FaceVertexAlphaData', [0*a; a], ...
'FaceAlpha', 'interp', 'EdgeColor', 'none', 'FaceColor', 'b');
ls = line('XData', t2, 'YData', y2,'Linewidth',1.5);
regions(4) = patch('XData', [t2; t2(end:-1:1)], ...
'YData', [y2 + 2*cov2; y2(end:-1:1)], ...
'FaceVertexAlphaData', [0*a; a], ...
'FaceAlpha', 'interp', 'EdgeColor', 'none', 'FaceColor', 'b');
then with swapping:
regions(1) = patch('XData', [t; t(end:-1:1)], ...
'YData', [y + 2*cov; y(end:-1:1)], ...
'FaceVertexAlphaData', [0*a; a], ...
'FaceAlpha', 'interp', 'EdgeColor', 'none', 'FaceColor', 'r');
regions(3) = patch('XData', [t2; t2(end:-1:1)], ...
'YData', [y2 - 2*cov2; y2(end:-1:1)], ...
'FaceVertexAlphaData', [0*a; a], ...
'FaceAlpha', 'interp', 'EdgeColor', 'none', 'FaceColor', 'b');
ls = line('XData', t2, 'YData', y2,'Linewidth',1.5);
regions(2) = patch('XData', [t; t(end:-1:1)], ...
'YData', [y - 2*cov; y(end:-1:1)], ...
'FaceVertexAlphaData', [0*a; a], ...
'FaceAlpha', 'interp', 'EdgeColor', 'none', 'FaceColor', 'r');
ls = line('XData', t, 'YData', y,'Linewidth',1.5);
regions(4) = patch('XData', [t2; t2(end:-1:1)], ...
'YData', [y2 + 2*cov2; y2(end:-1:1)], ...
'FaceVertexAlphaData', [0*a; a], ...
'FaceAlpha', 'interp', 'EdgeColor', 'none', 'FaceColor', 'b');
Great effect, I hadn't seen this before in Matlab.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With