本人终于写了第一篇博客
因毕业设计画图需要,用MATLAB写了一个自动画雷达图的程序,可以画两种雷达图:多边形风格和圆风格的雷达图,有需要的朋友可以参考。
画图的原理是,先一条一条画直线,然后再标注文字,然后填充图形。画直线用plot函数,标文字用text函数,填充图形用fill函数。这里有几个小技巧:
画图函数整合成draw_radar(data,lim,prefer_range,labels)函数,data是要画图的数据(根据数据的个数来确定雷达图的轴数),lim是各指标画图上下限范围,prefer_range是各指标参考上下限范围,labels是坐标轴名称。
function draw_radar(data,lim,prefer_range,labels)
n=length(data);
adj_data=zeros(n,1);
point=zeros(n,2);
adj_preferl=zeros(n,1);
preferl_point=zeros(n,2);
adj_preferu=zeros(n,1);
preferu_point=zeros(n,2);
set(gca,'units','normal','pos',[0 0 1 1]);
axis off
axis equal
hold on
theta_last=pi/2;
for i=1:n
theta=2*pi/n*i+pi/2;
plot([0,500*cos(theta)],[0,500*sin(theta)],'k-','linewidth',2);
for j=1:5
plot([j*100*cos(theta_last),j*100*cos(theta)],[j*100*sin(theta_last),j*100*sin(theta)],'--','linewidth',0.75,'color',[0.5,0.5,0.5]);
end
theta_last=theta;
if data(i)lim(i,2)
adj_data(i)=500;
else
adj_data(i)=(data(i)-lim(i,1))/(lim(i,2)-lim(i,1))*500;
end
point(i,1:2)=[adj_data(i)*cos(theta);adj_data(i)*sin(theta)];
adj_preferl(i)=(prefer_range(i,1)-lim(i,1))/(lim(i,2)-lim(i,1))*500;
preferl_point(i,1:2)=[adj_preferl(i)*cos(theta);adj_preferl(i)*sin(theta)];
adj_preferu(i)=(prefer_range(i,2)-lim(i,1))/(lim(i,2)-lim(i,1))*500;
preferu_point(i,1:2)=[adj_preferu(i)*cos(theta);adj_preferu(i)*sin(theta)];
text_around(510*cos(theta),510*sin(theta),labels{i},theta);
end
plot([preferl_point(:,1);preferl_point(1,1)],[preferl_point(:,2);preferl_point(1,2)],'b-','linewidth',1.5);
plot([preferu_point(:,1);preferu_point(1,1)],[preferu_point(:,2);preferu_point(1,2)],'r-','linewidth',1.5);
for i=1:n
theta=2*pi/n*i+pi/2;
for j=1:5
text_around(j*100*cos(theta),j*100*sin(theta),num2str(lim(i,1)+(lim(i,2)-lim(i,1))/5*j),theta+pi/2,7);
end
end
plot([point(:,1);point(1,1)],[point(:,2);point(1,2)],'k-','linewidth',0.2);
fill(point(:,1),point(:,2),[0.9 0.9 0.7])
alpha(0.5);
texts=findobj(gca,'Type','Text');
minx=-300;
maxx=300;
miny=-300;
maxy=300;
for i=1:length(texts)
rect=get(texts(i),'Extent');
x=rect(1);
y=rect(2);
dx=rect(3);
dy=rect(4);
if xmaxx
maxx=x+dx;
end
if ymaxy
maxy=y+dy;
end
end
axis([minx-50,maxx+50,miny-20,maxy+20]);
end
function text_around(x,y,txt,theta,fontsize)
if nargin==4
fontsize=10;
end
section=mod(theta+pi/12,2*pi);
if section>pi+pi/6
%上对齐
if section>1.5*pi+pi/6
%左对齐
text(x,y,txt,'VerticalAlignment','cap','HorizontalAlignment','left','Fontsize',fontsize);
elseif section>1.5*pi
%中对齐
text(x,y,txt,'VerticalAlignment','cap','HorizontalAlignment','center','Fontsize',fontsize);
else
%右对齐
text(x,y,txt,'VerticalAlignment','cap','HorizontalAlignment','right','Fontsize',fontsize);
end
elseif section>pi
%中、右对齐
text(x,y,txt,'VerticalAlignment','middle','HorizontalAlignment','right','Fontsize',fontsize);
elseif section>pi/6
%下对齐
if section>0.5*pi+pi/6
%右对齐
text(x,y,txt,'VerticalAlignment','bottom','HorizontalAlignment','right','Fontsize',fontsize);
elseif section>0.5*pi
%中对齐
text(x,y,txt,'VerticalAlignment','bottom','HorizontalAlignment','center','Fontsize',fontsize);
else
%左对齐
text(x,y,txt,'VerticalAlignment','bottom','HorizontalAlignment','left','Fontsize',fontsize);
end
else
%中、左对齐
text(x,y,txt,'VerticalAlignment','middle','HorizontalAlignment','left','Fontsize',fontsize);
end
end
函数调用的例子:
prefer=[4,7;20,50;85,95;75,85;1.2,2.5;5,6];
limit=[2,10;10,70;70,110;65,95;0.5,4;3,9];
clf;
draw_radar([6,35,96,70,2,5],limit,prefer,...
{'指标1/s','指标2/s','指标3/℃','指标4/℃','指标5/(g/s)','指标6/%'});
鉴于导师不太喜欢这种多边形的风格,又画了一种圆形风格的雷达图。当各指标都相等时,图像是一个完美的圆,否则会是一个凹凸不平的土豆(感觉比较丑,暂时没想到更好的办法,各位有更好的思路请留言~)。
画图的原理和多边形图基本相同,但有两处不太一样:
画图函数整合成draw_radar_circle(data,prefer_range,labels)函数,data是要画图的数据(根据数据的个数来确定雷达图的轴数),prefer_range是各指标参考上下限范围,labels是坐标轴名称。
function draw_radar_circle(data,prefer_range,labels)
n=length(data);
lim=zeros(n,2);
for j=1:n
lim(j,1)=prefer_range(j,1)-(prefer_range(j,2)-prefer_range(j,1));
lim(j,2)=prefer_range(j,2)+(prefer_range(j,2)-prefer_range(j,1));
end
adj_data=zeros(n,1);
adj_preferl=zeros(n,1);
preferl_point=zeros(n,2);
adj_preferu=zeros(n,1);
preferu_point=zeros(n,2);
set(gca,'units','normal','pos',[0 0 1 1]);
axis off
axis equal
hold on
for i=1:5
draw_circle(0,0,i*100,'--',[0.5,0.5,0.5],0.75);
end
for i=1:n
theta=2*pi/n*i+pi/2;
plot([0,500*cos(theta)],[0,500*sin(theta)],'k-','linewidth',2);
if data(i)lim(i,2)
adj_data(i)=500;
else
adj_data(i)=(data(i)-lim(i,1))/(lim(i,2)-lim(i,1))*500;
end
adj_preferl(i)=(prefer_range(i,1)-lim(i,1))/(lim(i,2)-lim(i,1))*500;
preferl_point(i,1:2)=[adj_preferl(i)*cos(theta);adj_preferl(i)*sin(theta)];
adj_preferu(i)=(prefer_range(i,2)-lim(i,1))/(lim(i,2)-lim(i,1))*500;
preferu_point(i,1:2)=[adj_preferu(i)*cos(theta);adj_preferu(i)*sin(theta)];
text_around(510*cos(theta),510*sin(theta),labels{i},theta);
end
draw_circle(0,0,500/3,'-',[0.2,0.2,0.9],1.5);
draw_circle(0,0,500/3*2,'-',[0.9,0.2,0.2],1.5);
for i=1:n
theta=2*pi/n*i+pi/2;
for j=1:5
text_around(j*100*cos(theta),j*100*sin(theta),num2str(lim(i,1)+(lim(i,2)-lim(i,1))/5*j),theta+pi/2,7);
end
end
y=[adj_data;adj_data(1)];
x=[2*pi/n*(1:n)'+pi/2;2*pi/n*(n+1)+pi/2];
m=length(x)*2-1;
x_2=zeros(m,1);
y_2=zeros(m,1);
for i=1:m
if mod(i,2)==0
x_2(i)=(x(i/2)+x(i/2+1))/2;
y_2(i)=(y(i/2)+y(i/2+1))/2;
else
x_2(i)=x((i+1)/2);
y_2(i)=y((i+1)/2);
end
end
xx=linspace(x_2(1),x_2(end),100);
yy=spline_period(x_2,y_2,xx);
point=zeros(length(yy),2);
for i=1:length(point)
point(i,1:2)=[yy(i)*cos(xx(i));yy(i)*sin(xx(i))];
end
fill(point(:,1),point(:,2),[0.9 0.9 0.7])
alpha(0.5);
texts=findobj(gca,'Type','Text');
minx=-500;
maxx=500;
miny=-500;
maxy=500;
for i=1:length(texts)
rect=get(texts(i),'Extent');
x=rect(1);
y=rect(2);
dx=rect(3);
dy=rect(4);
if xmaxx
maxx=x+dx;
end
if ymaxy
maxy=y+dy;
end
end
axis([minx-50,maxx+50,miny-20,maxy+20]);
end
function [] = draw_circle(x,y,r,line_type,color,linewidth)
theta=0:0.01:2*pi;
circlex=x+r*cos(theta);
circley=y+r*sin(theta);
plot(circlex,circley,line_type,'color',color,'linewidth',linewidth);
end
function yy=spline_period(x,y,xx)
n=length(x)-1; %n与书上的定义相同
h=zeros(n,1);
lambda=zeros(n,1);
mu=zeros(n,1);
g=zeros(n,1);
for k=1:n
h(k)=x(k+1)-x(k); %h(i)与书上的标号相同
end
for k=1:(n-1) %计算μ和λ
mu(k)=h(k)/(h(k+1)+h(k));
lambda(k)=1-mu(k);
g(k)=6/(h(1+k)+h(k))*((y(k+2)-y(k+1))/h(k+1)-(y(k+1)-y(k))/h(k));
end
mu(n)=h(n)/(h(1)+h(n));
lambda(n)=1-mu(n);
g(n)=6/(h(1)+h(n))*((y(2)-y(1))/h(1)-(y(n+1)-y(n))/h(n));
A=zeros(n,n);
for k=1:(n-1)
A(k,k)=2;
A(k,k+1)=lambda(k);
A(k+1,k)=mu(k+1);
end
A(n,n)=2;
A(1,n)=mu(1);
A(n,1)=lambda(n);
[L,U,p] = lu(A,'vector');
M = U\(L\(g(p,:)));
M=[M(n);M]; %M0,M1,M2..Mn
yy=zeros(size(xx));
k=2;
for i=1:length(xx)
if xx(i)>x(k) && kpi+pi/6
%上对齐
if section>1.5*pi+pi/6
%左对齐
text(x,y,txt,'VerticalAlignment','cap','HorizontalAlignment','left','Fontsize',fontsize);
elseif section>1.5*pi
%中对齐
text(x,y,txt,'VerticalAlignment','cap','HorizontalAlignment','center','Fontsize',fontsize);
else
%右对齐
text(x,y,txt,'VerticalAlignment','cap','HorizontalAlignment','right','Fontsize',fontsize);
end
elseif section>pi
%中、右对齐
text(x,y,txt,'VerticalAlignment','middle','HorizontalAlignment','right','Fontsize',fontsize);
elseif section>pi/6
%下对齐
if section>0.5*pi+pi/6
%右对齐
text(x,y,txt,'VerticalAlignment','bottom','HorizontalAlignment','right','Fontsize',fontsize);
elseif section>0.5*pi
%中对齐
text(x,y,txt,'VerticalAlignment','bottom','HorizontalAlignment','center','Fontsize',fontsize);
else
%左对齐
text(x,y,txt,'VerticalAlignment','bottom','HorizontalAlignment','left','Fontsize',fontsize);
end
else
%中、左对齐
text(x,y,txt,'VerticalAlignment','middle','HorizontalAlignment','left','Fontsize',fontsize);
end
end
函数调用的例子:
prefer=[4,7;20,50;85,95;75,85;1.2,2.5;5,6];
clf;
draw_radar_circle([6,35,96,70,2,5],prefer,...
{'指标1/s','指标2/s','指标3/℃','指标4/℃','指标5/(g/s)','指标6/%'});
当图像为5个坐标轴时,效果如下,用一个完美的雷达图来收尾。
多边形风格:
圆风格: