matlab - poligono - histograma de una imagen
Creando un histograma polar (2)
Esto parecía un problema interesante, así que lo intenté. El código puede necesitar algunos ajustes (como se describe en la parte inferior), pero puede obtener una idea general sobre cómo trazar algo como esto. Como verán, indirectamente estoy usando la sugerencia de Suever con respecto a los diagramas de rose
.
No estoy seguro de cuándo puedo encontrar el tiempo para perfeccionar esto, así que si alguien quiere ayudar a mejorar esto, hágamelo saber y voy a abrir un repositorio de Github.
function q38054152
%% Define resolution:
W = 5; % the step size in degrees, larger value = smaller resolution
P = 20; % the "radius" of the external disc (corresponds to the 100%)
%% Generate some data:
M = (1:W:360).'';
T = deg2rad(M);
N = numel(M);
S = cell(N,1); for x=1:N,S{x}=feval(@(x)x(1),strsplit(evalc(''why'')));end
% add some empty regions
M([randi(N,1,5) 30:36]) = NaN;
S(isnan(M)) = cell(1,sum(isnan(M)));
%% Ensure R >= B >= G:
% Generate histogram inputs:
cR = P*ones(N,1); % baseline is fully red
cB = randi(P+1,N,1)-1;
cG = randi(P+1,N,1)-1;
% Replicate:
R = deg2rad(repelem(M, min( cR ,[],2)));
B = deg2rad(repelem(M, min([cR,cB] ,[],2)));
G = deg2rad(repelem(M, min([cR,cB,cG],[],2)));
clear cR cB cG
%% Plot:
figure();
hR(1) = rose(R,T); hR(1).Color = [227 025 027]./255; hold on;
hR(2) = rose(B,T); hR(2).Color = [054 125 183]./255;
hR(3) = rose(G,T); hR(3).Color = [076 174 073]./255;
%% Fun with plot:
figure(''Color'',[1 1 1]);
% Convert lines to polygons:
patch(''XData'', hR(1).XData,''YData'', hR(1).YData, ''FaceColor'', hR(1).Color, ''EdgeColor'', ''w'');
axis square; axis off; box off; hold on;
patch(''XData'', hR(2).XData,''YData'', hR(2).YData, ''FaceColor'', hR(2).Color, ''EdgeColor'', ''none'');
patch(''XData'', hR(3).XData,''YData'', hR(3).YData, ''FaceColor'', hR(3).Color, ''EdgeColor'', ''none'');
% Remove center (method 1: mask with patch)
xC = cosd(1:360); yC = sind(1:360);
patch(''XData'', 0.2*P*xC,''YData'', 0.2*P*yC, ''FaceColor'', [1 1 1], ''EdgeColor'', ''none'');
% Remove center (method 2: relocate RGB patches using cart2pol and adjusting the inner R)
% Todo
% Draw "grid":
F = 0.2+0.8*(100-[10 20 40 80])/100;
for ind = 1:numel(F)
line(xC*F(ind)*P,yC*F(ind)*P,''Color'',[1 1 1],''LineWidth'',0.1);
end
% Add annotations:
for ind = 1:numel(M)
if isnan(M(ind))
continue
end
text(xC(M(ind))*P*1.05,yC(M(ind))*P*1.05,S{ind},''Rotation'', mod(M(ind)+90,180)-90,...
''HorizontalAlignment'',iftr(M(ind) < 90 || M(ind) > 270,''left'',''right''));
end
function out = iftr(cond,in1,in2)
%IFTR is a ternary operator implementation
% note: unlike "&&" and "||" this function does not have lazy evaluation capabilities,
% thus both inputs need to be known before this function executes.
if cond
out = in1;
else
out = in2;
end
Intermediamente también obtenemos esto:
Errores / problemas conocidos:
- Los objetos de
patch
que se extraen de los objetos deline
veces crean bordes donde no debería haber ninguno, lo que resulta en algunas formas extrañas en la trama (esto sucede la mayoría del tiempo con datos generados aleatoriamente, ejecútelo y verá lo que media). - Los valores de R / G / B deben escalarse, al igual que las líneas de la cuadrícula, para tener en cuenta el círculo blanco en el centro que ocupa el 20% del radio.
- La cuadrícula de los anillos blancos debe ser anotada (es decir, "20%", "40%", etc.). Se debe encontrar alguna forma inteligente de ubicarlos de modo que interfieran con los datos lo menos posible.
- Algunos códigos se replican en lugar de colocarse en una función.
- La
legend
encuentra.
Los histogramas polares pueden ser muy útiles para trazar gráficos de barras apiladas con entradas múltiples. Se proporciona un ejemplo en la imagen debajo del objetivo de la figura. Esto se puede hacer de alguna manera fácilmente en R con ggplot2. Una función similar a ''rosa'' en matlab no parece permitir tal resultado.
Como punto de partida, esto es lo que tengo:
- Guión
% inputs
l = [1 1.4 2 5 1 5 10;
10 5 1 5 2 1.4 1;
5 6 3 1 3 2 4];
alpha = [10 20 50 30 25 60 50]; % in degrees
label = 1:length(alpha);
% setings
offset = 1;
alpha_gap = 2;
polarHist(l,alpha,label)
Función
polarHist
function polarHist(data,alpha,theta_label,offset,alpha_gap,ticks)
if nargin 360-alpha_gap*length(alpha)
error(''Covers more than 360°'')
end
% code
theta_right = 90 - alpha_gap + cumsum(-alpha) - alpha_gap*[0:length(alpha)-1];
theta_left = theta_right + alpha;
col = get(gca,''colororder'');
for j = 1:size(data,1)
hold all
if j == 1
rho_in = kron(offset*ones(1,length(alpha)),[1 1]);
else
rho_in = rho_ext;
end
rho_ext = rho_in + kron(data(j,:),[1 1]);
for k = 1:size(data,2)
h = makewedge(rho_in(k),rho_ext(k),theta_left(k),theta_right(k),col(j,:));
if j == size(data,1) && ~isempty(theta_label)
theta = theta_right(k) + (theta_left(k) - theta_right(k))/2;
rho = rho_ext(k)+1;
[x,y] = pol2cart(theta/180*pi,rho);
lab = text(x,y,num2str(theta_label(k),''%0.f''),''HorizontalAlignment'',''center'',''VerticalAlignment'',''bottom'');
set(lab, ''rotation'', theta-90)
end
end
end
axis equal
theta = linspace(pi/2,min(theta_right)/180*pi);
%ticks = [0 5 10 15 20];
rho_ticks = offset + ticks;
ax = polar([ones(length(ticks(2:end)),1)*theta]'',[rho_ticks(2:end)''*ones(1,length(theta))]'');
set(ax,''color'',''w'',''linewidth'',1.5)
axis off
for i=1:length(ticks)
[x,y] = pol2cart((90)/180*pi,rho_ticks(i));
text(x,y,num2str(ticks(i)),''HorizontalAlignment'',''right'');
end
- Función
makewedge
function hOut = makewedge(rho1, rho2, theta1, theta2, color)
%MAKEWEDGE Plot a wedge.
% MAKEWEDGE(rho1, rho2, theta1, theta2, color) plots a polar
% wedge bounded by the given inputs. The angles are in degrees.
%
% h = MAKEWEDGE(...) returns the patch handle.
ang = linspace(theta1/180*pi, theta2/180*pi);
[arc1.x, arc1.y] = pol2cart(ang, rho1);
[arc2.x, arc2.y] = pol2cart(ang, rho2);
x = [arc1.x arc2.x(end:-1:1)];
y = [arc1.y arc2.y(end:-1:1)];
newplot;
h = patch(x, y, color);
if ~ishold
axis equal tight;
end
if nargout > 0
hOut = h;
end
El resultado todavía está lejos de la salida de ggplot2
pero creo que esto es un comienzo. Estoy luchando para agregar leyenda (filas de l
) ...
Puede simplificar su problema usando hist
para obtener los contenedores acumulados para cada elemento, luego normalizarlo a porcentaje y trazarlo como barras apiladas polares mediante el uso de parches.
Por ejemplo, digamos que sus datos constan de 30 elementos con 1000 muestras cada uno, y cada muestra puede ser 1,2 o 3.
data=randi(3,1000,30); %create random data
[data_bins,~]=hist(data'',3); %Get the accumulated bins
data_bins=data_bins/1000; %Normalize values to percentages
Puede trazar barras apiladas normales para visualizar los datos
function stackedbar(ymatrix1)
% Create figure
figure1 = figure(''Color'',[1 1 1]);
% Create axes
axes1 = axes(''Parent'',figure1,...
''YTickLabel'',{''0'',''10%'',''20%'',''40%'',''80%'',''100%''},...
''YTick'',[0 10 20 40 80 100],...
''XTick'',[1:length(ymatrix1)],...
''FontWeight'',''bold'',...
''FontSize'',16);
xlim(axes1,[0 length(ymatrix1)+1]);
ylim(axes1,[0 100]);
hold(axes1,''all'');
% Create multiple lines using matrix input to bar
bar1 = bar(ymatrix1,''EdgeColor'',[1 1 1],''BarLayout'',''stacked'',...
''Parent'',axes1);
set(bar1(1),...
''FaceColor'',[0.137254908680916 0.372549027204514 0.647058844566345],...
''EdgeColor'',[0.137254908680916 0.372549027204514 0.647058844566345],...
''DisplayName'',''uno'');
set(bar1(2),...
''FaceColor'',[0.223529413342476 0.619607865810394 0.168627455830574],...
''EdgeColor'',[0.223529413342476 0.619607865810394 0.168627455830574],...
''DisplayName'',''dos'');
set(bar1(3),''FaceColor'',[0.850980401039124 0 0.0431372560560703],...
''EdgeColor'',[0.850980401039124 0 0.0431372560560703],...
''DisplayName'',''tres'');
% Create legend
legend1 = legend(axes1,''show'');
set(legend1,...
''Position'',[0.902123631386861 0.416961133287318 0.0826277372262772 0.16808336774016]);
plot([0,length(ymatrix1)],[10,10],''w'')
plot([0,length(ymatrix1)],[20,20],''w'')
plot([0,length(ymatrix1)],[40,40],''w'')
plot([0,length(ymatrix1)],[80,80],''w'')
Puede usar los mismos valores como coordenadas polares usando pol2cart
, y dibujando todas las barras de color iguales en un parche, puede invocar legend
en esos parches
function polarstackedbar(data,offset)
% Data is the normalized values and offset is the size of the white circle at the center
yticks=[10,20,40,80,100];
% Create figure
figure1 = figure(''Color'',[1 1 1]);
% Create axes
axes1 = axes(''Parent'',figure1,''ZColor'',[1 1 1],''YColor'',[1 1 1],...
''XColor'',[1 1 1],...
''PlotBoxAspectRatio'',[434 342.3 2.282],...
''FontWeight'',''bold'',...
''FontSize'',16,...
''DataAspectRatio'',[1 1 1]);
temp=[data(:,1)+data(:,2)+data(:,3)+offset,data(:,1)+data(:,2)+data(:,3)+offset,zeros(length(data),1)]'';
temp=temp(:);
temp=[0;temp];
temp2=[data(:,1)+data(:,2)+offset,data(:,1)+data(:,2)+offset,zeros(length(data),1)]'';
temp2=temp2(:);
temp2=[0;temp2];
temp3=[data(:,1)+offset,data(:,1)+offset,zeros(length(data),1)]'';
temp3=temp3(:);
temp3=[0;temp3];
th=(1:length(data))*3*pi/(2*length(data));
themp=[th;th;th];
themp=themp(:);
themp=[0;0;themp];
themp(end)=[];
% Create patch
[XData1,YData1]=pol2cart(themp,temp);
p1=patch(''Parent'',axes1,''YData'',YData1,...
''XData'',XData1,...
''FaceColor'',[0.850980401039124 0 0.0431372560560703],...
''EdgeColor'',[0.850980401039124 0 0.0431372560560703],...
''DisplayName'',''tres'');
% Create patch
[XData2,YData2]=pol2cart(themp,temp2);
p2=patch(''Parent'',axes1,''YData'',YData2,...
''XData'',XData2,...
''FaceColor'',[0.223529413342476 0.619607865810394 0.168627455830574],...
''EdgeColor'',[0.223529413342476 0.619607865810394 0.168627455830574],...
''DisplayName'',''dos'');
% Create patch
[XData3,YData3]=pol2cart(themp,temp3);
p3=patch(''Parent'',axes1,''YData'',YData3,...
''XData'',XData3,...
''FaceColor'',[0.137254908680916 0.372549027204514 0.647058844566345],...
''EdgeColor'',[0.137254908680916 0.372549027204514 0.647058844566345],...
''DisplayName'',''uno'');
% Create patch
[XData4,YData4]=pol2cart(themp,offset*ones(3*length(data)+1,1));
patch(''Parent'',axes1,''YData'',YData4,...
''XData'',XData4,...
''LineStyle'',''none'',...
''FaceColor'',[1 1 1]);
% Create legend
legend([p3,p2,p1]);
hold
% Create labels
for i=1:length(data)
[x,y]=pol2cart((i-0.5)*3*pi/(2*length(data)),offset+5+100);
h=text(x,y,num2str(i),''HorizontalAlignment'',''center'');
set(h,''rotation'',rad2deg((i-0.5)*3*pi/(2*length(data)))-90+90*sign(cos((i-0.5)*3*pi/(2*length(data)))));
[x,y]=pol2cart((i)*3*pi/(2*length(data)),offset+15+100);
plot([0,x],[0,y],''w'');
end
thetas=0:0.01:2*pi;
for tick=yticks
[X,Y]=pol2cart(thetas,tick+offset*ones(1,629));
plot(X,Y,''w'')
text(X(472)+15,Y(472),strcat(int2str(tick),''%''),''FontWeight'',''bold'',''FontSize'',16,''HorizontalAlignment'',''center'');
end