转载请注明本文链接
及文章作者:slandarer
全网唯一,MATLAB绘制各类螺旋图,还在为X轴过长而困扰吗?把X轴盘起来就可以优雅的绘图!!今天带来的是由本人开发的SSpiral MATLAB 工具包,真的是好久不见了,这次一登上账号就发现已经放开了留言
功能,大家可以在文末留言互动试试,本期工具函数绘图效果:
工具函数放在最后,先看基本用法:
使用教程
1 坐标区域创建
使用SSpiral(gca)
的形式创建坐标区域,通过obj.set()
函数设置各种属性:
% Create spiral-axes
SS = SSpiral(gca);
设置螺旋角度范围:
% Set theta limit
SS.set('TLim',[0,3*360])
SS.set('TLim',[120,3*360])
设置X轴Y轴范围:
% Set X-axis limit and Y-axis limit
SS.set('XLim',[0,120], 'YLim',[0,10])
自定义刻度:
SS.set('XTick',0:5:120)
调整刻度线长度:
% Set ticks and minor-ticks length
SS.set('TickLength',[.2,.15])
隐藏次刻度线:
SS.set('XMinorTick','off')
2 柱状图绘制
多次使用obj.bar()
函数,画好多组柱状图:
figure('Units','normalized', 'Position',[.1,.1,.6,.75])
% Create spiral-axes
SS1 = SSpiral(gca);
SS1.set('TLim',[0,2*360+180], 'XLim',[0,200]+.5, 'YLim',[0,1], 'XTick',0:5:200)
X = rand(1,200);
SS1.bar(X);
SS1.bar(X./2);
SS1.bar(X./4);
legend({'AAA','BBB'}, 'FontSize',12, 'FontName','Times New Roman')
画一组柱状图但是正负数不同颜色:
figure('Units','normalized', 'Position',[.1,.1,.6,.75])
% Create spiral-axes
SS2 = SSpiral(gca);
SS2.set('TLim',[0,2*360+180], 'XLim',[0,200]+.5, 'YLim',[-.5,.5], 'XTick',0:5:200)
X = rand(1,200) - .5;
X1 = X.*(X>0);
X2 = X.*(X<0);
SS2.bar(X1);
SS2.bar(X2);
legend({'AAA','BBB'}, 'FontSize',12, 'FontName','Times New Roman')
3 标签及背景色
figure('Units','normalized', 'Position',[.1,.1,.6,.75])
% Create spiral-axes
SS2 = SSpiral(gca);
SS2.set('TLim',[0,2*360+180], 'XLim',[0,200]+.5, 'YLim',[0,1], 'XTick',0:5:200)
% Set background color to light-blue
SS2.set('BackgroundColor',[228,243,245]./255)
X = rand(1,200);
SS2.bar(X, 'FaceColor',[253,193,202]./255, 'EdgeColor','w');
% Set tick-labels font
SS2.set('TickLabelFont', {'FontSize',10, 'FontName','Times New Roman', 'Color',[0,0,.5]})
4 堆叠柱状图
很简单就是输入多列的数据:
figure('Units','normalized', 'Position',[.1,.1,.6,.75])
% Create spiral-axes
SS1 = SSpiral(gca);
SS1.set('TLim',[0,2*360+180], 'XLim',[0,200]+.5, 'YLim',[0,2], 'XTick',0:5:200)
X = rand(200,2);
SS1.bar(X, 'FaceColor',[0.46,0.67,0.18; 0.30,0.74,0.93]);
legend({'AAA','BBB'}, 'FontSize',12, 'FontName','Times New Roman')
% =========================================================================
figure('Units','normalized', 'Position',[.1,.1,.6,.75])
% Create spiral-axes
SS2 = SSpiral(gca);
SS2.set('TLim',[0,2*360+180], 'XLim',[0,200]+.5, 'YLim',[-1,1], 'XTick',0:5:200)
X = rand(200,2)-.5;
SS2.bar(X, 'FaceColor',[0.46,0.67,0.18; 0.30,0.74,0.93]);
legend({'AAA','BBB'}, 'FontSize',12, 'FontName','Times New Roman')
5 面积图
基础绘制:
% area diagram on spiral-axes
figure('Units','normalized', 'Position',[.1,.1,.6,.75])
SS1 = SSpiral(gca);
SS1.set('TLim',[0,2*360+180], 'XLim',[1,200], 'YLim',[0,1], 'XTick',0:5:200)
Y = rand(200,1);
SS1.area(1:200,Y);
% =========================================================================
% area diagrams on spiral-axes
figure('Units','normalized', 'Position',[.1,.1,.6,.75])
SS2 = SSpiral(gca);
SS2.set('TLim',[0,2*360+180], 'XLim',[1,200], 'YLim',[0,1], 'XTick',0:5:200)
Y = rand(200,2);
SS2.area(1:200,Y(:,1));
SS2.area(1:200,Y(:,2));
正负数部分不同颜色:
% Different colors in the positive and negative parts
figure('Units','normalized', 'Position',[.1,.1,.6,.75])
SS3 = SSpiral(gca);
SS3.set('TLim',[0,2*360+180], 'XLim',[1,200], 'YLim',[-.5,.5], 'XTick',0:5:200)
Y = rand(200,1)-.5;
Y = interp1(1:200, Y ,(1:.1:200).');
SS3.area(1:.1:200,Y.*(Y>0));
SS3.area(1:.1:200,Y.*(Y<0));
堆叠面积图:
% 堆叠面积图
% stacked-area diagram
figure('Units','normalized', 'Position',[.1,.1,.6,.75])
SS4 = SSpiral(gca);
SS4.set('TLim',[0,2*360+180], 'XLim',[1,200], 'YLim',[0,1.8], 'XTick',0:5:200)
Y = rand(200,2);
SS4.area(1:200,Y);
legend({'AAA','BBB'}, 'FontSize',12, 'FontName','Times New Roman')
含负数堆叠面积图:
% 含有负数的堆叠面积图
% Containing negative numbers stacked-area diagram
figure('Units','normalized', 'Position',[.1,.1,.6,.75])
SS5 = SSpiral(gca);
SS5.set('TLim',[0,2*360+180], 'XLim',[1,200], 'YLim',[-1,1], 'XTick',0:5:200)
Y = rand(200,2)-.5;
Y = interp1(1:200, Y ,1:.1:200);
SS5.area(1:.1:200,Y);
6 折线图与标签格式
通过设置TickLabelFormat
属性来设置标签格式,应该输入一个将数值转化为字符串的函数,通过XTickLabel
,YTickLabel
设置标签文本:
figure('Units','normalized', 'Position',[.1,.1,.6,.75])
SS = SSpiral(gca);
SS.set('TLim',[0,3*360], 'XLim',[0,240], 'YLim',[0,1], 'XTick',0:20/3:240)
Y = rand(121,2);
SS.plot(repmat((0:2:240)',[1,2]),Y, 'LineWidth',1, 'Marker', 'o');
pause(1)
% 修改标签格式为最简分数
% Change the label format to the simplest fraction
SS.set('TickLabelFormat',@(x) strtrim(rats(x)))
pause(1)
% 修改标签格式为指定字符串
strCell = [num2cell(char(32*ones(1,25))),{'January','February','March','April','May','June','July','August','September','October','November','December'}];
SS.set('XTickLabel',strCell)
SS.set('TickLabelFont',{'FontSize',14, 'FontName','Times New Roman'})
7 散点图
figure('Units','normalized', 'Position',[.1,.1,.6,.75])
SS = SSpiral(gca);
SS.set('TLim',[0,2*360+180], 'XLim',[1,200], 'YLim',[0,1], 'XTick',0:5:200)
Y = rand(1,100);
SS.scatter(1:2:200,Y,'filled', 'CData',[129,170,174]./255, 'Marker','o');
8 高亮区域
使用obj.xregion(lim)
和obj.yregion(lim)
函数:
figure('Units','normalized', 'Position',[.1,.1,.6,.75])
SS = SSpiral(gca);
SS.set('TLim',[0,2*360+180], 'XLim',[1,200], 'YLim',[0,1], 'XTick',0:5:200)
% X-region and Y-region
SS.xregion([50,100]);
SS.yregion([.7,1], 'FaceColor',[129,170,174]./255)
9 综合运用:聚类树
rng(3)
% draw dendrogram
Data = rand(200,3);
N = 5;
Z = linkage(Data,'average');
T = cluster(Z,'maxclust',N);
cutoff = median([Z(end-(N-1),3), Z(end-(N-2),3)]);
[LineSet, ~, order] = dendrogram(Z, 0, 'Orientation', 'top');
XSet = reshape([LineSet(:).XData], 4, []);
YSet = reshape([LineSet(:).YData], 4, []);
YSet = max(max(YSet))-YSet;
close all
figure('Units','normalized', 'Position',[.1,.1,.6,.75])
SS = SSpiral(gca);
SS.set('TLim',[0,2*360+180], 'XLim',[0,200]+.5, 'YLim',[0,max(max(YSet))], 'XTick',0:5:200)
% use function obj.line to draw lines with different length
SS.line(XSet, YSet, 'Color','k', 'LineWidth',1);
CList = [ 0.3569 0.0784 0.0784
0.6784 0.4471 0.1725
0.1020 0.3882 0.5176
0.1725 0.4196 0.4392
0.2824 0.2275 0.2902
0 0 0];
TT = T(order);
classNum = unique(TT, 'stable');
for i = 1:N
tX = [find(TT==classNum(i),1,'first')-.5, find(TT==classNum(i),1,'last')+.5];
lgdHdl(i) = SS.xregion(tX, 'FaceColor',CList(i,:), 'FaceAlpha',.4);
end
legend(lgdHdl, {'Set-S','Set-L','Set-A','Set-N','Set-M'})
工具函数完整代码
classdef SSpiral < handle
% Copyright (c) 2024, Zhaoxu Liu / slandarer
% =========================================================================
% @author : slandarer
% 公众号 : slandarer随笔
% 知乎 : slandarer
% -------------------------------------------------------------------------
% Zhaoxu Liu / slandarer (2024). Spiral diagram
% (https://www.mathworks.com/matlabcentral/fileexchange/164966-spiral-diagram),
% MATLAB Central File Exchange. Retrieved May 1, 2024.
properties
ax,
XLim, XTick, XMinorTick = 'on';
YLim, YTick,
Height = 1;
BackgroundColor = [239,239,239]./255
TLim = [0, 2*360]
TickLength = [.055, .02];
TickColor = [0,0,0];
TickWidth = 1;
XTickLabel
YTickLabel
TickLabelFont = {'FontSize',10, 'FontName','Times New Roman'}
TickLabelFormat = @(x) num2str(x)
arginList = {'XLim', 'YLim', 'TLim', 'XTick', 'YTick', 'Height',...
'BackgroundColor', 'TickLength', 'TickColor', 'TickWidth',...
'TickLabelFont', 'TickLabelFormat', 'TickLabel', ...
'XMinorTick', 'YMinorTick', 'XTickLabel', 'YTickLabel'}
ColorOrder = [ 0.2392 0.4627 0.6392
0.3686 0.6784 0.7451
0.3686 0.6314 0.4627
0.6549 0.3804 0.1373
0.4784 0.2510 0.0941
0.7059 0.5529 0.2824
0.4627 0.4902 0.4627];
ColorOrderIndex = 1;
BkgHdl, XTickHdl, XMinorTickHdl, YTickHdlS, YTickHdlE
end
% =========================================================================
methods
function obj = SSpiral(ax)
if nargin < 1, ax = gca; end
obj.ax = ax;
obj.ax.NextPlot = 'add';
obj.ax.XGrid = 'off';
obj.ax.YGrid = 'off';
obj.ax.Box = 'off';
obj.ax.XColor = 'none';
obj.ax.YColor = 'none';
obj.ax.DataAspectRatio = [1,1,1];
help SSpiral
obj.drawAxes(0)
end
% =========================================================================
function set(obj, varargin)
for i = 1:2:(length(varargin)-1)
tid = ismember(obj.arginList, varargin{i});
if any(tid)
obj.(obj.arginList{tid}) = varargin{i+1};
end
end
obj.drawAxes(1)
end
% =========================================================================
function drawAxes(obj, flag)
tT = linspace(obj.TLim(1), obj.TLim(2), ceil(abs(diff(obj.TLim)))+10)./180.*pi;
tX1 = (3.77 + 1.4.*abs(tT-obj.TLim(1)./180.*pi)).*cos(tT);
tY1 = (3.77 + 1.4.*abs(tT-obj.TLim(1)./180.*pi)).*sin(tT);
tL = vecnorm([tX1;tY1]);
tX2 = tX1./tL.*(tL + obj.Height.*2.*pi);
tY2 = tY1./tL.*(tL + obj.Height.*2.*pi);
tX = [tX1, tX2(end:-1:1)];
tY = [tY1, tY2(end:-1:1)];
if flag == 0
obj.BkgHdl = fill(obj.ax, tX,tY,obj.BackgroundColor, 'EdgeColor','none');
obj.BkgHdl.Annotation.LegendInformation.IconDisplayStyle='off';
else
set(obj.BkgHdl, 'XData',tX, 'YData',tY, 'FaceColor',obj.BackgroundColor)
end
if ~isempty(obj.XLim) && ~isempty(obj.YLim)
if isempty(obj.XTick)
tXT = obj.getTick(obj.XLim, (abs(diff(obj.TLim))/360)*10);
else
tXT = obj.XTick;
tXT(tXT<obj.XLim(1)) = [];
tXT(tXT>obj.XLim(2)) = [];
end
if isempty(obj.YTick)
tYT = obj.getTick(obj.YLim, 2);
else
tYT = obj.XTick;
tYT(tYT<obj.YLim(1)) = [];
tYT(tYT>obj.YLim(2)) = [];
end
% ---------------------------------------------------------
tMXTD = diff(tXT);
tMXT = tXT(1) - tMXTD(1) : tMXTD(1)/5 : tXT(end) + tMXTD(1);
tMXT(tMXT<obj.XLim(1)) = [];
tMXT(tMXT>obj.XLim(2)) = [];
% ---------------------------------------------------------
tT = (tXT-obj.XLim(1))./abs(diff(obj.XLim)).*abs(diff(obj.TLim)).*2.*((diff(obj.TLim)>0)-.5) + obj.TLim(1);
tT = tT./180.*pi;
tX1 = (3.77 + 1.4.*abs(tT-obj.TLim(1)./180.*pi)).*cos(tT);
tY1 = (3.77 + 1.4.*abs(tT-obj.TLim(1)./180.*pi)).*sin(tT);
tL = vecnorm([tX1; tY1]);
tX2 = tX1./tL.*(tL + obj.Height.*2.*pi);
tY2 = tY1./tL.*(tL + obj.Height.*2.*pi);
tX3 = tX1./tL.*(tL + obj.Height.*2.*pi + obj.TickLength(1).*2.*pi);
tY3 = tY1./tL.*(tL + obj.Height.*2.*pi + obj.TickLength(1).*2.*pi);
tX = [tX2; tX3; tX2.*nan]; tX = tX(:);
tY = [tY2; tY3; tY2.*nan]; tY = tY(:);
% ---------------------------------------------------------
tMT = (tMXT-obj.XLim(1))./abs(diff(obj.XLim)).*abs(diff(obj.TLim)).*2.*((diff(obj.TLim)>0)-.5) + obj.TLim(1);
tMT = tMT./180.*pi;
tMX1 = (3.77 + 1.4.*abs(tMT-obj.TLim(1)./180.*pi)).*cos(tMT);
tMY1 = (3.77 + 1.4.*abs(tMT-obj.TLim(1)./180.*pi)).*sin(tMT);
tML = vecnorm([tMX1; tMY1]);
tMX2 = tMX1./tML.*(tML + obj.Height.*2.*pi);
tMY2 = tMY1./tML.*(tML + obj.Height.*2.*pi);
tMX3 = tMX1./tML.*(tML + obj.Height.*2.*pi + obj.TickLength(2).*2.*pi);
tMY3 = tMY1./tML.*(tML + obj.Height.*2.*pi + obj.TickLength(2).*2.*pi);
tMX = [tMX2; tMX3; tMX2.*nan]; tMX = tMX(:);
tMY = [tMY2; tMY3; tMY2.*nan]; tMY = tMY(:);
% ---------------------------------------------------------
if isempty(obj.XTickHdl)
obj.XTickHdl = plot(tX, tY, 'Color',obj.TickColor, 'LineWidth',obj.TickWidth);
obj.XTickHdl.Annotation.LegendInformation.IconDisplayStyle='off';
else
set(obj.XTickHdl, 'XData',tX, 'YData',tY, 'Color',obj.TickColor, 'LineWidth',obj.TickWidth)
end
if isempty(obj.XMinorTickHdl)
obj.XMinorTickHdl = plot(tMX, tMY, 'Color',obj.TickColor, 'LineWidth',obj.TickWidth, 'Visible',obj.XMinorTick);
obj.XMinorTickHdl.Annotation.LegendInformation.IconDisplayStyle='off';
else
set(obj.XMinorTickHdl, 'XData',tMX, 'YData',tMY, 'Color',obj.TickColor, 'LineWidth',obj.TickWidth, 'Visible',obj.XMinorTick)
end
% ---------------------------------------------------------
tObj = findobj(obj.ax,'Tag','SSpiralTxt'); delete(tObj);
for i = 1:length(tX3)
tR = -90+tT(i)/pi*180;
if isempty(obj.XTickLabel)
tLbl = obj.TickLabelFormat(tXT(i));
else
tLbl = obj.XTickLabel{min(i,length(obj.XTickLabel))};
end
if mod(tT(i)/pi*180, 360) >180
tR = tR +180;
text(obj.ax,tX3(i),tY3(i),tLbl,...
'HorizontalAlignment','center', 'VerticalAlignment','top',...
'Rotation', tR, obj.TickLabelFont{:},'Tag','SSpiralTxt')
else
text(obj.ax,tX3(i),tY3(i),tLbl,...
'HorizontalAlignment','center', 'VerticalAlignment','bottom',...
'Rotation', tR, obj.TickLabelFont{:},'Tag','SSpiralTxt')
end
end
% ---------------------------------------------------------
tX1 = cos(obj.TLim(1)/180*pi).*((tYT-obj.YLim(1))./abs(diff(obj.YLim)).*(obj.Height.*2.*pi) + 3.77);
tY1 = sin(obj.TLim(1)/180*pi).*((tYT-obj.YLim(1))./abs(diff(obj.YLim)).*(obj.Height.*2.*pi) + 3.77);
tT = (obj.TLim(1) - 2.*((diff(obj.TLim)>0)-.5).*(90 + 15))/180*pi;
tX2 = tX1 + cos(tT).*obj.TickLength(1).*2.*pi;
tY2 = tY1 + sin(tT).*obj.TickLength(1).*2.*pi;
tX3 = tX1 + cos(tT).*obj.TickLength(1).*1.5.*2.*pi;
tY3 = tY1 + sin(tT).*obj.TickLength(1).*1.5.*2.*pi;
tX = [tX1; tX2; tX2.*nan]; tX = tX(:);
tY = [tY1; tY2; tY2.*nan]; tY = tY(:);
if isempty(obj.YTickHdlS)
obj.YTickHdlS= plot(tX, tY, 'Color',obj.TickColor, 'LineWidth',obj.TickWidth);
obj.YTickHdlS.Annotation.LegendInformation.IconDisplayStyle='off';
else
set(obj.YTickHdlS, 'XData',tX, 'YData',tY, 'Color',obj.TickColor, 'LineWidth',obj.TickWidth)
end
tR = tT/pi*180;
for i = 1:length(tX2)
if isempty(obj.YTickLabel)
tLbl = obj.TickLabelFormat(tYT(i));
else
tLbl = obj.YTickLabel{min(i,length(obj.YTickLabel))};
end
if mod(tR, 360) > 90 && mod(tR, 360) < 270
text(obj.ax,tX3(i),tY3(i),tLbl,...
'HorizontalAlignment','right', 'VerticalAlignment','middle',...
'Rotation', tR + 180, obj.TickLabelFont{:},'Tag','SSpiralTxt')
else
text(obj.ax,tX3(i),tY3(i),tLbl,...
'HorizontalAlignment','left', 'VerticalAlignment','middle',...
'Rotation', tR, obj.TickLabelFont{:},'Tag','SSpiralTxt')
end
end
% ---------------------------------------------------------
tX1 = cos(obj.TLim(2)/180*pi).*((tYT-obj.YLim(1))./abs(diff(obj.YLim)).*(obj.Height.*2.*pi) + 3.77 + 1.4.*abs((obj.TLim(2)-obj.TLim(1))./180.*pi));
tY1 = sin(obj.TLim(2)/180*pi).*((tYT-obj.YLim(1))./abs(diff(obj.YLim)).*(obj.Height.*2.*pi) + 3.77 + 1.4.*abs((obj.TLim(2)-obj.TLim(1))./180.*pi));
tT = (obj.TLim(2) + 2.*((diff(obj.TLim)>0)-.5).*(90))/180*pi;
tX2 = tX1 + cos(tT).*obj.TickLength(1).*2.*pi;
tY2 = tY1 + sin(tT).*obj.TickLength(1).*2.*pi;
tX3 = tX1 + cos(tT).*obj.TickLength(1).*1.5.*2.*pi;
tY3 = tY1 + sin(tT).*obj.TickLength(1).*1.5.*2.*pi;
tX = [tX1; tX2; tX2.*nan]; tX = tX(:);
tY = [tY1; tY2; tY2.*nan]; tY = tY(:);
if isempty(obj.YTickHdlE)
obj.YTickHdlE = plot(tX, tY, 'Color',obj.TickColor, 'LineWidth',obj.TickWidth);
obj.YTickHdlE.Annotation.LegendInformation.IconDisplayStyle='off';
else
set(obj.YTickHdlE, 'XData',tX, 'YData',tY, 'Color',obj.TickColor, 'LineWidth',obj.TickWidth)
end
tR = tT/pi*180;
for i = 1:length(tX2)
if isempty(obj.YTickLabel)
tLbl = obj.TickLabelFormat(tYT(i));
else
tLbl = obj.YTickLabel{min(i,length(obj.YTickLabel))};
end
if mod(tR, 360) > 90 && mod(tR, 360) < 270
text(obj.ax,tX3(i),tY3(i),tLbl,...
'HorizontalAlignment','right', 'VerticalAlignment','middle',...
'Rotation', tR + 180, obj.TickLabelFont{:},'Tag','SSpiralTxt')
else
text(obj.ax,tX3(i),tY3(i),tLbl,...
'HorizontalAlignment','left', 'VerticalAlignment','middle',...
'Rotation', tR, obj.TickLabelFont{:},'Tag','SSpiralTxt')
end
end
end
axis tight
obj.ax.XLim = obj.ax.XLim + [-1,1].*max(obj.ax.XLim).*.1;
obj.ax.YLim = obj.ax.YLim + [-1,1].*max(obj.ax.YLim).*.1;
end
% =========================================================================
function ticks = getTick(~, XLim, N)
tXS = abs(diff(XLim)) / N;
tXN = ceil(log(tXS) / log(10));
tXS = round(round(tXS / 10^(tXN-2)) / 5) * 5 * 10^(tXN-2);
tON = ceil(log(abs(XLim(1))) / log(10));
tON(isinf(tON)) = 1;
tOS = round(round(XLim(1) / 10^(tON-2)) / 5) * 5 * 10^(tON-2);
ticks = tOS:tXS:XLim(2);
end
% =========================================================================
function barHdl = bar(obj, Y, varargin)
arginListBar = {'FaceColor', 'EdgeColor', 'FaceAlpha', 'EdgeAlpha',...
'LineWidth', 'BarWidth', 'CData'};
barProp.FaceColor = [];
barProp.EdgeColor = [0,0,0];
barProp.FaceAlpha = 1;
barProp.EdgeAlpha = 1;
barProp.LineWidth = .5;
barProp.BarWidth = 1;
if isempty(varargin) || ischar(varargin{1})
if size(Y,1) == 1
barProp.XData = 1:size(Y,2);
barProp.YData = Y;
else
barProp.XData = 1:size(Y,1);
barProp.YData = Y.';
end
else
barProp.XData = Y(:).';
barProp.YData = varargin{1}; varargin(1) = [];
if size(barProp.XData,1) == 1
else
barProp.YData = barProp.YData.';
end
end
for i = 1:2:(length(varargin)-1)
tid = ismember(arginListBar, varargin{i});
if any(tid)
barProp.(arginListBar{tid}) = varargin{i+1};
end
end
% if isempty(barProp.FaceColor)
% if size(barProp.YData,1) > 1
% barProp.FaceColor = obj.ColorOrder(mod(obj.ColorOrderIndex + (0:size(areaProp.YData,1)-1) -1, size(obj.ColorOrder,1)) + 1, :);
% obj.ColorOrderIndex = obj.ColorOrderIndex + size(areaProp.YData,1);
% else
% barProp.FaceColor = obj.ColorOrder(mod(obj.ColorOrderIndex-1, size(obj.ColorOrder,1)) + 1, :);
% obj.ColorOrderIndex = obj.ColorOrderIndex + 1;
% end
% end
if isempty(barProp.FaceColor)
barProp.FaceColor = obj.ColorOrder(mod(obj.ColorOrderIndex + (0:size(barProp.YData,1)-1) -1, size(obj.ColorOrder,1)) + 1, :);
obj.ColorOrderIndex = obj.ColorOrderIndex + size(barProp.YData,1);
end
bX1 = linspace(-.5.*barProp.BarWidth, .5.*barProp.BarWidth, 50);
CY1 = zeros(1,size(barProp.YData,2));
CY2 = zeros(1,size(barProp.YData,2));
% if size(barProp.YData,1) > 1
for i = 1:size(barProp.YData,1)
tX = repmat(barProp.XData(:), [1,100]) + repmat([bX1, bX1(end:-1:1)], [size(barProp.YData,2),1]);
tY = [repmat(barProp.YData(i,:).', [1,50]), zeros(size(barProp.YData,2),50)] + repmat(CY1(:).*(barProp.YData(i,:).'>0) + CY2(:).*(barProp.YData(i,:).'<0), [1,100]);
CY1 = CY1 + barProp.YData(i,:).*(barProp.YData(i,:)>0);
CY2 = CY2 + barProp.YData(i,:).*(barProp.YData(i,:)<0);
tT = (tX-obj.XLim(1))./abs(diff(obj.XLim)).*abs(diff(obj.TLim)).*2.*((diff(obj.TLim)>0)-.5) + obj.TLim(1);
tR = (tY-obj.YLim(1))./abs(diff(obj.YLim)).*(obj.Height.*2.*pi) + 3.77 + 1.4.*abs((tT-obj.TLim(1))./180.*pi);
tT = tT.'; tR = tR.';
barHdl(i,:) = fill(obj.ax, cos(tT./180.*pi).*tR,sin(tT./180.*pi).*tR, barProp.FaceColor(i,:), 'EdgeColor',barProp.EdgeColor,...
'LineWidth',barProp.LineWidth, 'FaceAlpha',barProp.FaceAlpha, 'EdgeAlpha',barProp.EdgeAlpha);
for j = 2:length(barHdl)
barHdl(i,j).Annotation.LegendInformation.IconDisplayStyle='off';
end
end
% else
% % for i = 1:size(barProp.YData,2)
% % tX = barProp.XData(i) + [-.5.*barProp.BarWidth, bX, .5.*barProp.BarWidth];
% % tY = [barProp.YData(i), zeros(1,50), barProp.YData(i)];
% % tT = (tX-obj.XLim(1))./abs(diff(obj.XLim)).*abs(diff(obj.TLim)).*2.*((diff(obj.TLim)>0)-.5) + obj.TLim(1);
% % tR = (tY-obj.YLim(1))./abs(diff(obj.YLim)).*(obj.Height.*2.*pi) + 3.77 + 1.4.*abs((tT-obj.TLim(1))./180.*pi);
% % barHdl(i) = fill(obj.ax, cos(tT/180*pi).*tR,sin(tT/180*pi).*tR, barProp.FaceColor, 'EdgeColor',barProp.EdgeColor,...
% % 'LineWidth',barProp.LineWidth, 'FaceAlpha',barProp.FaceAlpha, 'EdgeAlpha',barProp.EdgeAlpha);
% % end
% tX = repmat(barProp.XData(:), [1,100]) + repmat([bX1, bX1(end:-1:1)], [size(barProp.YData,2),1]);
% tY = [repmat(barProp.YData(:), [1,50]), zeros(size(barProp.YData,2),50)];
% tT = (tX-obj.XLim(1))./abs(diff(obj.XLim)).*abs(diff(obj.TLim)).*2.*((diff(obj.TLim)>0)-.5) + obj.TLim(1);
% tR = (tY-obj.YLim(1))./abs(diff(obj.YLim)).*(obj.Height.*2.*pi) + 3.77 + 1.4.*abs((tT-obj.TLim(1))./180.*pi);
% tT = tT.'; tR = tR.';
% barHdl = fill(obj.ax, cos(tT./180.*pi).*tR,sin(tT./180.*pi).*tR, barProp.FaceColor, 'EdgeColor',barProp.EdgeColor,...
% 'LineWidth',barProp.LineWidth, 'FaceAlpha',barProp.FaceAlpha, 'EdgeAlpha',barProp.EdgeAlpha);
% for i = 2:length(barHdl)
% barHdl(i).Annotation.LegendInformation.IconDisplayStyle='off';
% end
% end
end
function areaHdl = area(obj, X, Y, varargin)
arginListBar = {'FaceColor', 'EdgeColor', 'FaceAlpha', 'EdgeAlpha',...
'LineWidth', 'BarWidth', 'CData'};
areaProp.FaceColor = [];
areaProp.EdgeColor = 'none';
areaProp.FaceAlpha = .5;
areaProp.EdgeAlpha = 1;
areaProp.LineWidth = .5;
areaProp.XData = X(:).';
areaProp.YData = Y.';
for i = 1:2:(length(varargin)-1)
tid = ismember(arginListBar, varargin{i});
if any(tid)
areaProp.(arginListBar{tid}) = varargin{i+1};
end
end
if isempty(areaProp.FaceColor)
areaProp.FaceColor = obj.ColorOrder(mod(obj.ColorOrderIndex + (0:size(areaProp.YData,1)-1) -1, size(obj.ColorOrder,1)) + 1, :);
obj.ColorOrderIndex = obj.ColorOrderIndex + size(areaProp.YData,1);
end
bX1 = linspace(areaProp.XData(1), areaProp.XData(end), length(areaProp.XData)*10);
CY1 = zeros(1, length(areaProp.XData)*10);
CY2 = zeros(1, length(areaProp.XData)*10);
for i = 1:size(areaProp.YData,1)
tX = [bX1, bX1(end:-1:1)];
tYq = interp1(areaProp.XData, areaProp.YData(i,:), bX1);
tY = [tYq, zeros(1,length(bX1))] + [CY1,CY1(end:-1:1)].*([tYq,tYq(end:-1:1)]>0) + [CY2,CY2(end:-1:1)].*([tYq,tYq(end:-1:1)]<0);%repmat(CY1.*(tYq>0) + CY2.*(tYq<0), [1,2]);
CY1 = CY1 + tYq.*(tYq>0);
CY2 = CY2 + tYq.*(tYq<0);
tT = (tX-obj.XLim(1))./abs(diff(obj.XLim)).*abs(diff(obj.TLim)).*2.*((diff(obj.TLim)>0)-.5) + obj.TLim(1);
tR = (tY-obj.YLim(1))./abs(diff(obj.YLim)).*(obj.Height.*2.*pi) + 3.77 + 1.4.*abs((tT-obj.TLim(1))./180.*pi);
areaHdl(i) = fill(obj.ax, cos(tT./180.*pi).*tR,sin(tT./180.*pi).*tR, areaProp.FaceColor(i,:), 'EdgeColor',areaProp.EdgeColor,...
'LineWidth',areaProp.LineWidth, 'FaceAlpha',areaProp.FaceAlpha, 'EdgeAlpha',areaProp.EdgeAlpha);
end
end
function plotHdl = plot(obj, X, Y, varargin)
if any(size(X) == 1)
tN = length(X);
else
tN = size(X,1);
end
tTq = linspace(1, tN, (tN-1)*10+1);
tX = interp1(1:tN, X, tTq);
tY = interp1(1:tN, Y, tTq);
tT = (tX-obj.XLim(1))./abs(diff(obj.XLim)).*abs(diff(obj.TLim)).*2.*((diff(obj.TLim)>0)-.5) + obj.TLim(1);
tR = (tY-obj.YLim(1))./abs(diff(obj.YLim)).*(obj.Height.*2.*pi) + 3.77 + 1.4.*abs((tT-obj.TLim(1))./180.*pi);
plotHdl = plot(obj.ax, cos(tT./180.*pi).*tR,sin(tT./180.*pi).*tR, 'MarkerIndices',1:10:(tN-1)*10+1, varargin{:});
end
function lineHdl = line(obj, X, Y, varargin)
if any(size(X) == 1)
tN = length(X);
else
tN = size(X,1);
end
for i = 1:size(Y,2)
tNq = ceil((max(max(X(:,i)))-min(min(X(:,i))))./abs(diff(obj.XLim)).*abs(diff(obj.TLim)))/2+10;
tTq = linspace(1, tN, tNq);
tX = interp1(1:tN, X(:,i), tTq);
tY = interp1(1:tN, Y(:,i), tTq);
tT = (tX-obj.XLim(1))./abs(diff(obj.XLim)).*abs(diff(obj.TLim)).*2.*((diff(obj.TLim)>0)-.5) + obj.TLim(1);
tR = (tY-obj.YLim(1))./abs(diff(obj.YLim)).*(obj.Height.*2.*pi) + 3.77 + 1.4.*abs((tT-obj.TLim(1))./180.*pi);
lineHdl(i) = plot(obj.ax, cos(tT./180.*pi).*tR,sin(tT./180.*pi).*tR, varargin{:},'Marker','none');
end
end
function scatterHdl = scatter(obj, X, Y, varargin)
tT = (X-obj.XLim(1))./abs(diff(obj.XLim)).*abs(diff(obj.TLim)).*2.*((diff(obj.TLim)>0)-.5) + obj.TLim(1);
tR = (Y-obj.YLim(1))./abs(diff(obj.YLim)).*(obj.Height.*2.*pi) + 3.77 + 1.4.*abs((tT-obj.TLim(1))./180.*pi);
scatterHdl = scatter(obj.ax, cos(tT./180.*pi).*tR,sin(tT./180.*pi).*tR, varargin{:});
end
function regionHdl = xregion(obj, Lim, varargin)
Lim = (Lim-obj.XLim(1))./abs(diff(obj.XLim)).*abs(diff(obj.TLim)) + obj.TLim(1);
tT = linspace(Lim(1), Lim(2), ceil(abs(diff(Lim)))+10)./180.*pi;
tX1 = (3.77 + 1.4.*abs(tT-obj.TLim(1)./180.*pi)).*cos(tT);
tY1 = (3.77 + 1.4.*abs(tT-obj.TLim(1)./180.*pi)).*sin(tT);
tL = vecnorm([tX1;tY1]);
tX2 = tX1./tL.*(tL + obj.Height.*2.*pi);
tY2 = tY1./tL.*(tL + obj.Height.*2.*pi);
tX = [tX1, tX2(end:-1:1)];
tY = [tY1, tY2(end:-1:1)];
regionHdl = fill(obj.ax, tX,tY, [114,146,184]./255, 'EdgeColor','none', 'FaceAlpha',.5, varargin{:});
end
function regionHdl = yregion(obj, Lim, varargin)
tT = linspace(obj.TLim(1), obj.TLim(2), ceil(abs(diff(obj.TLim)))+10)./180.*pi;
tX1 = (3.77 + 1.4.*abs(tT-obj.TLim(1)./180.*pi)).*cos(tT);
tY1 = (3.77 + 1.4.*abs(tT-obj.TLim(1)./180.*pi)).*sin(tT);
tL = vecnorm([tX1;tY1]);
tX2 = tX1./tL.*(tL + obj.Height.*2.*pi.*(Lim(1)-obj.YLim(1))./abs(diff(obj.YLim)));
tY2 = tY1./tL.*(tL + obj.Height.*2.*pi.*(Lim(1)-obj.YLim(1))./abs(diff(obj.YLim)));
tX3 = tX1./tL.*(tL + obj.Height.*2.*pi.*(Lim(2)-obj.YLim(1))./abs(diff(obj.YLim)));
tY3 = tY1./tL.*(tL + obj.Height.*2.*pi.*(Lim(2)-obj.YLim(1))./abs(diff(obj.YLim)));
tX = [tX2, tX3(end:-1:1)];
tY = [tY2, tY3(end:-1:1)];
regionHdl = fill(obj.ax, tX,tY, [114,146,184]./255, 'EdgeColor','none', 'FaceAlpha',.5, varargin{:});
end
end
end
完
以上已经是完整代码,未经允许本代码请勿作商业用途,引用的话可以引用我file exchange上的链接,可使用如下格式:
Zhaoxu Liu / slandarer (2024). Spiral diagram (https://www.mathworks.com/matlabcentral/fileexchange/164966-spiral-diagram), MATLAB Central File Exchange. Retrieved May 1, 2024.
若转载请保留以上file exchange链接及本文链接!!!!!
该工具可通过上述fileexchange链接获取,或者通过以下gitee仓库下载: