Brandon Dube
Brandon Dube

Reputation: 448

Programmatically producing polar or quasi-polar plots with a variable for color in matlab

I would like to create plots using matlab that represent a numerical assessment of quality in a radial fashion.

The best method I've found seems to not work properly. One runs the following code:

theta = (0 : (360/11) : 360)*pi/180;
r = 0 : 2 : 20 ;
[TH,R] = meshgrid(theta,r);
[X,Y] = pol2cart(TH,R);
Z = meshgrid(Data);
surf(X,Y,Z);

Data is a vector of data containing 11 numbers, an example dataset being the following:

Data = 0.884, 0.882, 0.879, 0.880, 0.8776, 0.871, 0.8587, 0.829, 0.811, 0.803, 0.780 

the output of surf here is this:

Incorrect surf plot

I would like to produce a more refined version of this type of image:

mostly correct output

which I have generated with the following code:

for theta = 0 : pi/100 : pi;  
    v = [InterpolatedImageHeight;LengthVector];
    x_center = InterpolatedImageHeight((HorizontalRes+1)/2);
    y_center = 0; %InterpolatedImageHeight((HorizontalRes+1)/2);
    center = repmat([x_center; y_center], 1, length(InterpolatedImageHeight));
    R = [cos(theta) -sin(theta); sin(theta) cos(theta)];
    vo = R*(v - center) + center;
    x_rotated = vo(1,:);
    y_rotated = vo(2,:);
    scatter(x_rotated,y_rotated,DotSize,InterpolatedData,'filled'); %x,y,area,color,properties
end

The issue with this is that it is a scatter plot where I am essentially using plot(r,Data), plotting many many copies, and increasing the dot size. The graphic itself has many seams, this takes an enormous amount of memory, and is time intensive where surf or mesh will run extremely fast and take minimal memory.

How does one produce concentric rings with a variable input for color?

Upvotes: 0

Views: 219

Answers (2)

Brandon Dube
Brandon Dube

Reputation: 448

based on the code by Darren Rowland in this thread I have come up with the following solution:

x = interp1(1:length(data),datax,(datax(1):datax(end)/f:datax(end)),'linear'); 
y = interp1(1:length(datay),datay,datay(1):datay(end)/f:datay(end),'spline');
theta = linspace(0,2*pi,n);

xr = x.'*cos(theta);
zr = x.'*sin(theta);
yr = repmat(y.',1,n);

figure;
surf(xy,yr,zr,zr*numcolors);

which is elegant, runs quickly, and produces beautiful figures. This is a sample of the output with some extra chart elements:

sample chart produced by code: Canon EF 50mm f/1.4 Average MTF 30lp/mm map

Upvotes: 0

Matt
Matt

Reputation: 13923

There are two completely different plots in your question. The first one represents the data as rays from the origin towards the outside of the circle. The data-points are placed anti-clockwise. A refined version of this can be achieved like this:

Data = [0.884, 0.882, 0.879, 0.880, 0.8776, 0.871,...
        0.8587, 0.829, 0.811, 0.803, 0.780]; 

theta = linspace(0,2*pi,length(Data));
r = linspace(0,20,length(Data));
[TH,R] = meshgrid(theta,r);

Z = meshgrid(Data);
[X,Y,Z] = pol2cart(TH,R,Z);

surf(X,Y,Z);
view(2);
shading interp

Note that I used linspace to generate theta and r to always match the length of Data. Z is also passed trough pol2cart. Then you can use shading interp to remove the lines between the patches and interpolate the color. With view(2) you can set the perspective as you would have a 2d-plot.

This is the result:

result1


It's relatively easy to get a result like in your second example. There the data-points represent concentric circles around the origin and are placed from the origin towards the outside. Therefore, just transpose the meshgrid of Z by using the following line:

Z = meshgrid(Data)';

This is the result then:

result2

Upvotes: 1

Related Questions