• MATLAB | 两种上色方式的旭日图绘制


    嘿,这次真的是好久不见了,好不容易才有点空写点文章,这段时间忙到后台回复都有点来不及看,很抱歉有一部分后台留言刚看到就已经超过时限没法回复了,不过根据大家的留言,需求主要集中在希望出一期旭日图的教程,今天它来啦~

    旭日图要说简单也不简单,要说难也不算难,唯一难点估计就是将数据分类排好序,然后每一圈能对应起来呗,上色啥的也不算啥难点,因此这期就简单教大家如何把大框架画出来以及提供两种上色方式。

    还是挺酷的,近期没啥空单独开发出一个支持更多上色模式的类,大家可以先根据本文提供的代码先自行DIY着。


    教程部分

    0 数据

    这里懒得搜集数据,自己随机生成了一个table类型数据,前三列都是名称,最后一列是数值:

    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);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    大概长这样:


    1 数据处理

    利用 grp2idx 进行分类,利用 sortrows 将相同类归在一起

    % 利用 grp2idx 进行分类,利用 sortrows 将相同类归在一起
    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);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    2 属性预设

    设置配色,字体,文本显示的阈值等信息:

    % 此处可以设置配色
    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];
    % 在这可修改字体
    FontProp = {'FontSize',12,'Color',[0,0,0]};
    % 在这可设置比例低于多少的部分不显示文字
    TextThreshold = 0.012;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    3 绘图

    径向渐变

    % 开始绘图
    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];
            if i == 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&&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
    % 绘制最外圈饼状图
    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&&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
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59


    切向渐变

    % 开始绘图
    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];
            if i == 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&&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
    % 绘制最外圈饼状图
    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&&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
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80


    完整代码(径向)

    就是前面的代码顺着复制下来,可以换成自己的数据和颜色:
    篇幅有限就只先给出径向渐变完整代码,切向渐变代码就光把最后一段稍微一更换即可:

    % @author:slandarer
    
    %% ========================================================================
    % 随机生成一组数据,可将 Table 自行更换
    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);
    
    %% ========================================================================
    % 利用 grp2idx 进行分类,利用 sortrows 将相同类归在一起
    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);
    %% ========================================================================
    % 此处可以设置配色
    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];
    % 在这可修改字体
    FontProp = {'FontSize',12,'Color',[0,0,0]};
    % 在这可设置比例低于多少的部分不显示文字
    TextThreshold = 0.012;
    %% ========================================================================
    % 开始绘图
    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];
            if i == 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&&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
    % 绘制最外圈饼状图
    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&&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
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111

    以上以及是完整代码,若日后代码有更新可在以下gitee仓库查看:

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

  • 相关阅读:
    Redis简介
    神经网络分类算法是什么,神经网络分类算法简介
    腾讯云拼了99元服务器老用户能买,续费不涨价!
    没人带宝宝,所以才要送去托育园?
    小程序如何自定义navber,使用了navber需要注意的点
    FPGA 20个例程篇:18.SD卡存放音频WAV播放(上)
    OpenGL之着色器
    前端需要了解的颜色模型,RGB、HSL和HSV
    MindSearch:AI 时代的“思考型”搜索引擎
    机器人SLAM与自主导航
  • 原文地址:https://blog.csdn.net/slandarer/article/details/134025373