开发者

Plot circles with alpha values in MATLAB

I'm creating a scatter plot of some data, as you do, and I have a number of repeated data points which I'd like to plot as circles with some alpha value so that piling on of extra points at the same location is obvious.

As far as I can te开发者_StackOverflow社区ll you cannot set the alpha properties of the little circles that you generate with plot(x, y, 'o'), so I've resorted to drawing thousands of little circles using patch() myself:

x = repmat([1:10], [1 10]);
y = round(10*rand(100, 1))/10;
xlim([0 11])
ylim([0 1])
p = ag_plot_little_circles(x', y, 10, [1 0 .4], 0.2);

function p = ag_plot_little_circles(x, y, circle, col, alpha)
%AG_PLOT_LITTLE_CIRCLES Plot circular circles of relative size circle
% Returns handles to all patches plotted

    % aspect is width / height
    fPos = get(gcf, 'Position');
    % need width, height in data values
    xl = xlim();
    yl = ylim();
    w = circle*(xl(2)-xl(1))/fPos(3);
    h = circle*(yl(2)-yl(1))/fPos(4);

    theta = 0:pi/5:2*pi;
    mx = w*sin(theta);
    my = h*cos(theta);
    num = 0;
    for k = 1:max(size(x))
        for f = 1:size(y,2)
            num = num+1;
            p(num) = patch(x(k)+mx, y(k,f)+my, col, 'FaceColor', col, 'FaceAlpha', alpha, 'EdgeColor', 'none');
        end
    end
end

As you can see, this is not optimal as I need to know and set the size of the plot (xlim and ylim) before I plot it so that the circles end up being circular. If I reshape the plot then they end up as ovals. I also end up with millions of objects, which is a pain when making legends.

Is there an easier way?


I have found no way to have a line marker with alpha in MATLAB.

If you look at line properties (the (mid) low level function behind plot), you will see that you can define markers, and their sole properties are their color (MarkerEdgeColor or MarkerFaceColor), which does not take any alpha (there is no MarkerFaceAlpha property).

So how you do it with patches seems the way to go.

The only thing I can propose to avoid having zillions of objects would be to group them in a hggroup, which will make them appear as a single object in the legend.


I tried to do a general function using patch. It's slow and a bit buggy, but it works OK for simple cases. MATLAB needs a real-line alpha though.

x and y are points to plot, w the width of the line, col the color and a the alpha value.

Example:

x = linspace(-2,2,100);
plotWithAlpha(x,sin(4*x),0.04,'r',0.2)


function [] = plotWithAlpha(x,y,w,col,a)
%function [] = plotWithAlpha(x,y,w,col,a)
    if(size(x,1) ~= 1)
       x = x.';
    end

    if(size(x,1) ~= 1)
       y = y.';
    end

    sz = length(x);

    % Calculate derrivatives of the curve
    X = csaps(1:sz(1),x,1);
    Y = csaps(1:sz(1),y,1);

    mx = fnval(fnder(X,1),1:sz(1)).';
    my = fnval(fnder(Y,1),1:sz(1)).';

    T = [mx my]; %tangent

    % Normalize tangents
    T = bsxfun(@rdivide,T,sqrt(sum(T.^2,2)));

    N = zeros(size(T));

    N(:,2) = 1;
    N(:,1) = -T(:,2)./T(:,1);

    N = bsxfun(@rdivide,N,sqrt(sum(N.^2,2)));

    N = N.';

    hold on

    for i = 2:length(x)
        X = [x(i-1)+w*N(1,i-1) x(i)+w*N(1,i) x(i-1)-w*N(1,i-1) x(i)-w*N(1,i)];
        Y = [y(i-1)+w*N(2,i-1) y(i)+w*N(2,i) y(i-1)-w*N(2,i-1) y(i)-w*N(2,i)];

        % Order the points
        D = pdist([X' Y']);
        D = squareform(D); D(D==0) = Inf;

        inds = 1;
        D(:,1) = Inf;

        [val ind] = min(D(1,:));
        inds(2) = ind;
        D(:,ind) = Inf;

        [val ind] = min(D(ind,:));
        inds(3) = ind;
        D(:,ind) = Inf;

        inds(4) = setxor(inds,1:4);

        X = X(inds);
        Y = Y(inds);

        patch(X,Y,col,'edgeColor','none','FaceAlpha',a)
    end

    hold off


I have the same problem, and my scatter plot has 100,000's of points. The idea of answer #2 is great, but it was impractical for me to open my plot in Illustrator because I had too many points. So I adapted answer #2 into a batch process:

print the figure to a pdf file in matlab:

print -dpdf foo.pdf

convert the pdf file to svg using pdf2svg from debian package pdf2svg:

pdf2svg foo.pdf foo.svg

make all blue objects transparent:

sed '/rgb(0%,0%,100%)/s/fill-opacity:1/fill-opacity:.2' < foo.svg > foo2.svg

convert foo2.svg to pdf using rsvg-convert from debian package librsvg2-bin:

rsvg-convert -f pdf -o foo2.pdf foo2.svg


Found the patchline function on the Matlab Exchange that can take any patch arguments including 'FaceAlpha':

http://www.mathworks.com/matlabcentral/fileexchange/36953-patchline/content/patchline.m


As far I can tell, there is no way to directly set alpha for markers in MATLAB. Patch methods fail to work well when alpha is set below about 0.03 or when there are far more than 10,000 markers.

The workaround to generate publication quality graphics when you have a dense cloud of markers is to give the markers a unique color. Then print the figure to EPS. Then open in Illustrator, select all objects of that color and set the transparency and color of the objects in Illustrator. It's not the one-step solution one would hope for, but it does give much, much better looking results than using internal MATLAB functions and is quick, provided you have Illustrator or an equivalent vector graphics package.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜