MATLAB | Sunburst drawing with two coloring methods

Hey, it’s been a long time since I last saw you. I finally have some free time to write some articles. I was so busy during this period that I didn’t even have time to read the replies in the background. I’m sorry that some of the comments in the background have exceeded the time limit as soon as I saw them. However, according to everyone’s comments, the demand is mainly for a tutorial on the rising sun chart, and it’s here today~

The sunburst chart is neither simple nor difficult. The only difficulty is probably to classify the data and sort it so that each circle can correspond to it. Coloring and other things are not difficult, so this issue I will simply teach you how to draw a large frame and provide two methods of coloring.

It’s quite cool. I don’t have much time to develop a class that supports more coloring modes in the near future. You can DIY it first based on the code provided in this article.

Tutorial section

0 data

I am too lazy to collect data here, so I randomly generated a table type data. The first three columns are names, and the last column is numerical values:

rng(1)
ULList = 'ABCD';
LLList = 'abcd';

rowNum = 50;
idx1 = randi([1,length(ULList)],[1,rowNum]);
idx2 = randi([1,3],[rowNum,1]);
Name1 = ULList(idx1'*ones(1,4));
Name2 = [LLList(idx1'*ones(1,4)),num2str(idx2)];
Name3 = [LLList(idx1)',num2str(idx2),...
         char(45.*ones(rowNum,1)),char(randi([97,122],[rowNum,5]))];
Value = rand([rowNum,1]);
Table = table(Name1,Name2,Name3,Value);

It probably looks like this:

1 Data processing

Use grp2idx for classification and sortrows to group the same categories together

% Use grp2idx for classification and sortrows to group the same categories together.
NameList = Table.Properties.VariableNames;
NameNum = length(NameList)-1;
NameCell{<!-- -->NameNum} = ' ';
valueList = zeros(length(Table.(NameList{<!-- -->1})),NameNum);
for i = 1:NameNum-1
    tName = Table.(NameList{<!-- -->i});
    tUniq = unique(tName,'rows');
    NameCell{<!-- -->i} = tUniq;
    ind = grp2idx([tUniq;tName]);
    ind(1:length(tUniq)) = [];
    valueList(:,i) = ind;
end
valueList(:,end) = -Table.(NameList{<!-- -->end});
[VAL,IDX] = sortrows(valueList,1:size(valueList,2));
VAL(:,end) = -VAL(:,end);

2 Attribute default

Set color matching, fonts, text display thresholds and other information:

% Here you can set the color matching
CList=[0.3882 0.5333 0.7059
    1.0000 0.6824 0.2039
    0.9373 0.4353 0.4157
    0.5490 0.7608 0.7922
    0.3333 0.6784 0.5373
    0.7647 0.7373 0.2471
    0.7333 0.4627 0.5765
    0.7294 0.6275 0.5804
    0.6627 0.7098 0.6824
    0.4627 0.4627 0.4627];
% You can modify the font here
FontProp = {<!-- -->'FontSize',12,'Color',[0,0,0]};
% Here you can set the proportion below which text will not be displayed.
TextThreshold = 0.012;

3 Drawing

Radial Gradient

% Start drawing
figure('Units','normalized','Position',[.2,.1,.52,.72]);
ax = gca; hold on
ax.DataAspectRatio = [1,1,1];
ax.XColor = 'none';
ax.YColor = 'none';
tT = linspace(0,1,100);
for i = 1:size(VAL,2)-1
    tRateSum = 0;
    tNum = length(NameCell{<!-- -->i});
    for j = 1:tNum
        tRate = sum(VAL(VAL(:,i) == j,end))./sum(VAL(:,end));
        tTheta = [tRateSum + tT.*tRate,tRateSum + tRate-tT.*tRate].*pi.*2;
        tR = [tT.*0 + i,tT.*0 + i + 1];
        ifi==1
            fill(cos(tTheta).*tR,sin(tTheta).*tR,CList(j,:),'EdgeColor',[1,1,1],'LineWidth',1)
        else
            tCN = VAL(find(VAL(:,i) == j,1),1);
            fill(cos(tTheta).*tR,sin(tTheta).*tR,...
                CList(tCN,:).*0.8^(i-1) + [1,1,1].*(1-0.8^(i-1)),'EdgeColor',[1,1,1] ,'LineWidth',1)
        end
        
        rotation = (tRateSum + tRate/2)*360;
        if tRate > TextThreshold
        if rotation>90 & amp; & amp;rotation<270
            rotation=rotation + 180;
            text(cos((tRateSum + tRate/2).*pi.*2)*i,sin((tRateSum + tRate/2).*pi.*2)*i,NameCell{<!-- -->i }(j,:) + " ",FontProp{<!-- -->:},...
                'Rotation',rotation,'HorizontalAlignment','right')
        else
            text(cos((tRateSum + tRate/2).*pi.*2)*i,sin((tRateSum + tRate/2).*pi.*2)*i," " + NameCell{<!- - -->i}(j,:),FontProp{<!-- -->:},...
                'Rotation',rotation)
        end
        end
        tRateSum = tRateSum + tRate;
    end
end
% Draw the outermost circle pie chart
tRateSum = 0;
tNameCell = Table.(NameList{<!-- -->end-1});
for j = 1:size(VAL,1)
    tRate = VAL(j,end)./sum(VAL(:,end));
    tTheta = [tRateSum + tT.*tRate,tRateSum + tRate-tT.*tRate].*pi.*2;
    tR = [tT.*0 + size(VAL,2),tT.*0 + size(VAL,2) + 1];
    tCN = VAL(j,1);
    fill(cos(tTheta).*tR,sin(tTheta).*tR,CList(tCN,:).*0.8^(size(VAL,2)-1) + ...
        [1,1,1].*(1-0.8^(size(VAL,2)-1)),'EdgeColor',[1,1,1],'LineWidth',1)
    rotation = (tRateSum + tRate/2)*360;
    if tRate > TextThreshold
    if rotation>90 & amp; & amp;rotation<270
        rotation=rotation + 180;
        text(cos((tRateSum + tRate/2).*pi.*2)*size(VAL,2),sin((tRateSum + tRate/2).*pi.*2)*size(VAL,2), tNameCell(IDX(j),:) + " ",FontProp{<!-- -->:},...
            'Rotation',rotation,'HorizontalAlignment','right')
    else
        text(cos((tRateSum + tRate/2).*pi.*2)*size(VAL,2),sin((tRateSum + tRate/2).*pi.*2)*size(VAL,2), " " + tNameCell(IDX(j),:),FontProp{<!-- -->:},...
            'Rotation',rotation)
    end
    end
    tRateSum = tRateSum + tRate;
end

Tangential gradient

% Start drawing
figure('Units','normalized','Position',[.2,.1,.52,.72]);
ax = gca; hold on
ax.DataAspectRatio = [1,1,1];
ax.XColor = 'none';
ax.YColor = 'none';
tT = linspace(0,1,100);
LCList = CList(1:length(NameCell{<!-- -->1}),:);
for i = 1:size(VAL,2)-1
    tRateSum = 0;
    tNum = length(NameCell{<!-- -->i});
    NCList = zeros(tNum,3);
    for j = 1:tNum
        tRate = sum(VAL(VAL(:,i) == j,end))./sum(VAL(:,end));
        tTheta = [tRateSum + tT.*tRate,tRateSum + tRate-tT.*tRate].*pi.*2;
        tR = [tT.*0 + i,tT.*0 + i + 1];
        ifi==1
            fill(cos(tTheta).*tR,sin(tTheta).*tR,CList(j,:),'EdgeColor',[1,1,1],'LineWidth',1)
        else
            tCN = VAL(find(VAL(:,i) == j,1),i-1);
            tNN = j-VAL(find(VAL(:,i-1) == tCN,1),i) + 1;
            tPN = length(unique(VAL(VAL(:,i-1) == tCN,i)));
            if mod(i,2)~=0
                tRN = tNN;
            else
                tRN = tPN + 1-tNN;
            end
            NCList(j,:)=LCList(tCN,:).*0.8^(tRN-1) + [1,1,1].*(1-0.8^(tRN-1));
            fill(cos(tTheta).*tR,sin(tTheta).*tR,NCList(j,:),'EdgeColor',[1,1,1],'LineWidth',1)
        end
        
        rotation = (tRateSum + tRate/2)*360;
        if tRate > TextThreshold
        if rotation>90 & amp; & amp;rotation<270
            rotation=rotation + 180;
            text(cos((tRateSum + tRate/2).*pi.*2)*i,sin((tRateSum + tRate/2).*pi.*2)*i,NameCell{<!-- -->i }(j,:) + " ",FontProp{<!-- -->:},...
                'Rotation',rotation,'HorizontalAlignment','right')
        else
            text(cos((tRateSum + tRate/2).*pi.*2)*i,sin((tRateSum + tRate/2).*pi.*2)*i," " + NameCell{<!- - -->i}(j,:),FontProp{<!-- -->:},...
                'Rotation',rotation)
        end
        end
        tRateSum = tRateSum + tRate;
    end
    if i ~=1
        LCList=NCList;
    end
end
% Draw the outermost circle pie chart
tRateSum = 0;
tNameCell = Table.(NameList{<!-- -->end-1});
NCList = zeros(size(VAL,1),3);
for j = 1:size(VAL,1)
    tRate = VAL(j,end)./sum(VAL(:,end));
    tTheta = [tRateSum + tT.*tRate,tRateSum + tRate-tT.*tRate].*pi.*2;
    tR = [tT.*0 + size(VAL,2),tT.*0 + size(VAL,2) + 1];

    tCN = VAL(j,size(VAL,2)-1);
    tNN = j-find(VAL(:,size(VAL,2)-1) == tCN,1) + 1;
    tPN = sum(VAL(:,size(VAL,2)-1) == tCN);
    if mod(size(VAL,2),2)~=0
        tRN = tNN;
    else
        tRN = tPN + 1-tNN;
    end
    NCList(j,:)=LCList(tCN,:).*0.8^(tRN-1) + [1,1,1].*(1-0.8^(tRN-1));
    fill(cos(tTheta).*tR,sin(tTheta).*tR,NCList(j,:),'EdgeColor',[1,1,1],'LineWidth',1)
    rotation = (tRateSum + tRate/2)*360;
    if tRate > TextThreshold
    if rotation>90 & amp; & amp;rotation<270
        rotation=rotation + 180;
        text(cos((tRateSum + tRate/2).*pi.*2)*size(VAL,2),sin((tRateSum + tRate/2).*pi.*2)*size(VAL,2), tNameCell(IDX(j),:) + " ",FontProp{<!-- -->:},...
            'Rotation',rotation,'HorizontalAlignment','right')
    else
        text(cos((tRateSum + tRate/2).*pi.*2)*size(VAL,2),sin((tRateSum + tRate/2).*pi.*2)*size(VAL,2), " " + tNameCell(IDX(j),:),FontProp{<!-- -->:},...
            'Rotation',rotation)
    end
    end
    tRateSum = tRateSum + tRate;
end

Complete code (radial)

Just copy the previous code and replace it with your own data and colors:
Due to limited space, I will only give the complete code for the radial gradient first, and the code for the tangential gradient will just replace the last paragraph slightly:

% @author:slandarer

%% ================================================ ========================
% Randomly generate a set of data, and the Table can be replaced by itself
rng(1)
ULList = 'ABCD';
LLList = 'abcd';

rowNum = 50;
idx1 = randi([1,length(ULList)],[1,rowNum]);
idx2 = randi([1,3],[rowNum,1]);
Name1 = ULList(idx1'*ones(1,4));
Name2 = [LLList(idx1'*ones(1,4)),num2str(idx2)];
Name3 = [LLList(idx1)',num2str(idx2),...
         char(45.*ones(rowNum,1)),char(randi([97,122],[rowNum,5]))];
Value = rand([rowNum,1]);
Table = table(Name1,Name2,Name3,Value);

%% ================================================ ========================
% Use grp2idx for classification and sortrows to group the same categories together
NameList = Table.Properties.VariableNames;
NameNum = length(NameList)-1;
NameCell{NameNum} = ' ';
valueList = zeros(length(Table.(NameList{1})),NameNum);
for i = 1:NameNum-1
    tName = Table.(NameList{i});
    tUniq = unique(tName,'rows');
    NameCell{i} = tUniq;
    ind = grp2idx([tUniq;tName]);
    ind(1:length(tUniq)) = [];
    valueList(:,i) = ind;
end
valueList(:,end) = -Table.(NameList{end});
[VAL,IDX] = sortrows(valueList,1:size(valueList,2));
VAL(:,end) = -VAL(:,end);
%% ================================================ ========================
% Color matching can be set here
CList=[0.3882 0.5333 0.7059
    1.0000 0.6824 0.2039
    0.9373 0.4353 0.4157
    0.5490 0.7608 0.7922
    0.3333 0.6784 0.5373
    0.7647 0.7373 0.2471
    0.7333 0.4627 0.5765
    0.7294 0.6275 0.5804
    0.6627 0.7098 0.6824
    0.4627 0.4627 0.4627];
% You can modify the font here
FontProp = {'FontSize',12,'Color',[0,0,0]};
% Here you can set the proportion below which text will not be displayed.
TextThreshold = 0.012;
%% ================================================ ========================
% Start drawing
figure('Units','normalized','Position',[.2,.1,.52,.72]);
ax = gca; hold on
ax.DataAspectRatio = [1,1,1];
ax.XColor = 'none';
ax.YColor = 'none';
tT = linspace(0,1,100);
for i = 1:size(VAL,2)-1
    tRateSum = 0;
    tNum = length(NameCell{<!-- -->i});
    for j = 1:tNum
        tRate = sum(VAL(VAL(:,i) == j,end))./sum(VAL(:,end));
        tTheta = [tRateSum + tT.*tRate,tRateSum + tRate-tT.*tRate].*pi.*2;
        tR = [tT.*0 + i,tT.*0 + i + 1];
        ifi==1
            fill(cos(tTheta).*tR,sin(tTheta).*tR,CList(j,:),'EdgeColor',[1,1,1],'LineWidth',1)
        else
            tCN = VAL(find(VAL(:,i) == j,1),1);
            fill(cos(tTheta).*tR,sin(tTheta).*tR,...
                CList(tCN,:).*0.8^(i-1) + [1,1,1].*(1-0.8^(i-1)),'EdgeColor',[1,1,1] ,'LineWidth',1)
        end
        
        rotation = (tRateSum + tRate/2)*360;
        if tRate > TextThreshold
        if rotation>90 & amp; & amp;rotation<270
            rotation=rotation + 180;
            text(cos((tRateSum + tRate/2).*pi.*2)*i,sin((tRateSum + tRate/2).*pi.*2)*i,NameCell{<!-- -->i }(j,:) + " ",FontProp{<!-- -->:},...
                'Rotation',rotation,'HorizontalAlignment','right')
        else
            text(cos((tRateSum + tRate/2).*pi.*2)*i,sin((tRateSum + tRate/2).*pi.*2)*i," " + NameCell{<!- - -->i}(j,:),FontProp{<!-- -->:},...
                'Rotation',rotation)
        end
        end
        tRateSum = tRateSum + tRate;
    end
end
% Draw the outermost circle pie chart
tRateSum = 0;
tNameCell = Table.(NameList{<!-- -->end-1});
for j = 1:size(VAL,1)
    tRate = VAL(j,end)./sum(VAL(:,end));
    tTheta = [tRateSum + tT.*tRate,tRateSum + tRate-tT.*tRate].*pi.*2;
    tR = [tT.*0 + size(VAL,2),tT.*0 + size(VAL,2) + 1];
    tCN = VAL(j,1);
    fill(cos(tTheta).*tR,sin(tTheta).*tR,CList(tCN,:).*0.8^(size(VAL,2)-1) + ...
        [1,1,1].*(1-0.8^(size(VAL,2)-1)),'EdgeColor',[1,1,1],'LineWidth',1)
    rotation = (tRateSum + tRate/2)*360;
    if tRate > TextThreshold
    if rotation>90 & amp; & amp;rotation<270
        rotation=rotation + 180;
        text(cos((tRateSum + tRate/2).*pi.*2)*size(VAL,2),sin((tRateSum + tRate/2).*pi.*2)*size(VAL,2), tNameCell(IDX(j),:) + " ",FontProp{<!-- -->:},...
            'Rotation',rotation,'HorizontalAlignment','right')
    else
        text(cos((tRateSum + tRate/2).*pi.*2)*size(VAL,2),sin((tRateSum + tRate/2).*pi.*2)*size(VAL,2), " " + tNameCell(IDX(j),:),FontProp{<!-- -->:},...
            'Rotation',rotation)
    end
    end
    tRateSum = tRateSum + tRate;
end

End

The above is the complete code. If the code is updated in the future, you can view it in the following gitee repository:

https://gitee.com/slandarer/spdraw/