MATLAB | 繪圖復刻(二十一)| 扇形熱圖+小提琴圖

前段時間在小紅書刷到了一個很有特色的熱力圖,由大佬@滾筒洗衣機創作,感覺很有意思,嘗試 MATLAB 復刻:

作者使用的是 python 代碼,趕快去瞅瞅。

復刻效果

正文部分

0.數據準備

數據需要一個用來畫熱圖的矩陣以及一個和矩陣相同列數的數組或者元胞數組。例如:

% 例子1 隨便構造數據
% 隨便構造的數據,可以換成自己的數據
clc; clear; rng(4)
Data = rand([7, 12]) + 1 + sin(linspace(0, 2*pi, 12) - pi/1.2) + (1:7).'./12;
Data = Data./max(max(Data));% 繪制小提琴圖的數據,應為列數與 Data 相同的矩陣或元胞數組
VData = mean(Data, 1) + randn([50, size(Data, 2)]).*.6;

這組數據畫出來大概長這樣:

此外假如我有兩行數據,一行是日期,一行是數值,我們也可以直接將這組數據進行處理,統計其均值來畫熱圖,然后按照每個月的數據分類畫小提琴圖,例如我們讓 chatGPT 生成一組數據:

% 對chatGPT:
% 使用matlab構造一組數據,為2018第一天到2024年最后一天的數據,要求具有季節性clc;clear
% 創建日期向量
t = datetime(2018,1,1):days(1):datetime(2024,12,31);
n = length(t);% 將日期轉換為一年中的位置(1 到 365/366)
day_of_year = day(t, 'dayofyear');
year_length = year(t);  % 判斷閏年時有用
is_leap = eomday(year(t),2) == 29;% 構造季節性數據:例如正弦函數,每年重復一次(周期365)
% 基本模式:sin(2*pi * day_of_year / 365)
% 添加噪聲 + 趨勢(可選)
seasonal = 10 * sin(2*pi * day_of_year ./ 365);   % 季節性(年周期)
noise = randn(1, n).*5;                           % 噪聲
trend = 0.01 * (1:n);                             % 微小上升趨勢% 最終數據
v = seasonal + noise + trend;% 可視化
plot(t, v)
xlabel('Date')
ylabel('Value')
title('Synthetic Seasonal Data (2018–2024)')Data.t = t;
Data.v = v;
save test.mat Data

這組數據大概長這樣:

我們讀取存儲的數據并進行統計:

% 例子2 已有各年份每一天數據,對其進行統計
clc; clear
testData = load('test.mat');
t = testData.Data.t;
v = testData.Data.v;
y = 2024:-1:2018;
% 構造一個矩陣,第 i 行第 j 列是第 i 年第 j 個月的數值平均值
Data = zeros(length(y), 12);
for i = 1:length(y)for m = 1:12idx = (year(t) == y(i)) & (month(t) == m);Data(i, m) = mean(v(idx));end
end
% 構造一個元胞數組,第 i 個元胞是 i 月全部數值合集
VData{12} = [];
for m = 1:12idx = (month(t) == m);VData{m} = v(idx)';
end

這組數據畫出圖來形狀如下:

當然還需要定義行標簽和列標簽:

% 矩陣每行名稱
% rowName = {'2024','2023','2022','2021',2020','2019','2018'};
rowName = compose('%d',2024:-1:2018);% 矩陣每列名稱
colName = {'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', ...'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'};

1.基礎樣式

基本不太用動,數據范圍及刻度位置不設置的話會自動計算,那個被注釋掉的配色就是我嘗試仿照原作者弄的配色:

% 標簽格式
fontProp = {'FontSize',16, 'FontName','Times New Roman'};% 配色
CMap = 'summer';
% CMap = interp1([0,.5,1], [214,115,144;255,238,234;107,152,191]./255, 0:.01:1);% 小提琴圖寬度
width = 0.9;% 數據范圍,以及刻度位置
% VLim = [0, 1];
% VTick = 0:.2:1;
VLim = [];
VTick = [];


完整代碼

因為繪圖部分比較長,我這里直接放一下帶著前面數據定義的完整代碼得了:

% ----------------------------------------------------------------------
% 例子1 隨便構造數據
% 隨便構造的數據,可以換成自己的數據
clc; clear; rng(4)
Data = rand([7, 12]) + 1 + sin(linspace(0, 2*pi, 12) - pi/1.2) + (1:7).'./12;
Data = Data./max(max(Data));% 繪制小提琴圖的數據,應為列數與 Data 相同的矩陣或元胞數組
VData = mean(Data, 1) + randn([50, size(Data, 2)]).*.6;% ----------------------------------------------------------------------
% % 例子2 已有各年份每一天數據,對其進行統計
% clc; clear
% testData = load('test.mat');
% t = testData.Data.t;
% v = testData.Data.v;
% y = 2024:-1:2018;
% % 構造一個矩陣,第 i 行第 j 列是第 i 年第 j 個月的數值平均值
% Data = zeros(length(y), 12);
% for i = 1:length(y)
%     for m = 1:12
%         idx = (year(t) == y(i)) & (month(t) == m);
%         Data(i, m) = mean(v(idx));
%     end
% end
% % 構造一個元胞數組,第 i 個元胞是 i 月全部數值合集
% VData{12} = [];
% for m = 1:12
%     idx = (month(t) == m);
%     VData{m} = v(idx)';
% end% 矩陣每行名稱
% rowName = {'2024','2023','2022','2021',2020','2019','2018'};
rowName = compose('%d',2024:-1:2018);% 矩陣每列名稱
colName = {'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', ...'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'};%% 格式設置 ===============================================================
% 標簽格式
fontProp = {'FontSize',16, 'FontName','Times New Roman'};% 配色
CMap = 'summer';
% CMap = interp1([0,.5,1], [214,115,144;255,238,234;107,152,191]./255, 0:.01:1);% 小提琴圖寬度
width = 0.9;% 數據范圍,以及刻度位置
% VLim = [0, 1];
% VTick = 0:.2:1;
VLim = [];
VTick = [];%% 數據預處理 ============================================================
% 如果不設置 VLim, VTick
% 則自動計算一個比較合理的刻度位置
linearTickCompactDegree = 5;
if isempty(VLim)if iscell(VData)VLim = [min(min(min(Data)), min(cellfun(@min, VData)))...max(max(max(Data)), max(cellfun(@max, VData)))];elseVLim = [min(min(min(Data)), min(min(VData)))...max(max(max(Data)), max(max(VData)))];end
end
if isempty(VTick)tXS = diff(VLim) / linearTickCompactDegree;tXN = ceil(log(tXS) / log(10));tXS = round(round(tXS / 10^(tXN-2)) / 5) * 5 * 10^(tXN-2);tVTick1 = 0:-tXS:VLim(1);tVTick2 = 0:tXS:VLim(2);VTick = unique([tVTick1, tVTick2]);VTick(VTick < VLim(1)) = [];VTick(VTick > VLim(2)) = [];
end%% 繪圖部分代碼 ============================================================
% 構造圖窗及坐標區域
fig = figure('Units','normalized', 'Position',[.1,.1,.6,.8], 'Color','w');
ax = axes('Parent',fig, 'XLim',[-sqrt(3), sqrt(3)], 'YLim',[0, 2], ...'DataAspectRatio',[1,1,1], 'Position',[.05,.2,.9,.8], ...'NextPlot','add', 'XColor','none', 'YColor','none');
colormap(CMap)% 繪制射線
w = 1*pi/3/size(Data, 2);
tt = linspace(5*pi/6 - w, pi/6 + w, size(Data, 2));
xx = cos(tt).*2; xx = [xx; xx.*0; xx.*nan(1)];
yy = sin(tt).*2; yy = [yy; yy.*0; yy.*nan(1)];
plot(ax, xx(:), yy(:), 'LineWidth',1, 'Color',[1,1,1].*.8, 'LineStyle','--')% 繪制列標簽
for i = 1:length(colName)text(ax, cos(tt(i)).*2.01, sin(tt(i)).*2.01, colName(i), ...'HorizontalAlignment','center', 'VerticalAlignment', 'bottom', ...'Rotation', tt(i)/pi*180 - 90, fontProp{:})
end% 繪制行名稱標簽
for i = 1:length(rowName)r = 2/5 + (size(Data, 1) - i + .5)*4/size(Data, 1)/5;if mod(i, 2) == 1text(ax, cos(5*pi/6).*r - 1/100, sin(5*pi/6).*r - sqrt(3)/100, rowName{i}, ...'HorizontalAlignment','right', 'Rotation',60, fontProp{:})elsetext(ax, cos(pi/6).*r + 1/100, sin(pi/6).*r - sqrt(3)/100, rowName{i}, ...'HorizontalAlignment','left', 'Rotation',-60, fontProp{:})end
end% 繪制刻度軸線
plot(ax, cos(5*pi/6).*[6/5 + 1/10, 10/5 - 1/10], ...sin(5*pi/6).*[6/5 + 1/10, 10/5 - 1/10], 'LineWidth',1, 'Color','k')
plot(ax, cos(pi/6).*[6/5 + 1/10, 10/5 - 1/10], ...sin(pi/6).*[6/5 + 1/10, 10/5 - 1/10], 'LineWidth',1, 'Color','k')% 繪制刻度和刻度標簽
for i = 1:length(VTick)r = (VTick(i) - VLim(1))./diff(VLim).*(3/5) + (6/5 + 1/10);x1 = [cos(5*pi/6).*r, cos(5*pi/6).*r + 1/100];y1 = [sin(5*pi/6).*r, sin(5*pi/6).*r + sqrt(3)/100];plot(ax, x1, y1, 'LineWidth',1, 'Color','k')x2 = [cos(pi/6).*r, cos(pi/6).*r - 1/100];y2 = [sin(pi/6).*r, sin(pi/6).*r + sqrt(3)/100];plot(ax, x2, y2, 'LineWidth',1, 'Color','k')if mod(length(VTick) - i, 2) == 0text(ax, cos(5*pi/6).*r - 1/100, sin(5*pi/6).*r - sqrt(3)/100, num2str(VTick(i)), ...'HorizontalAlignment','right', 'Rotation',60, fontProp{:})elsetext(ax, cos(pi/6).*r + 1/100, sin(pi/6).*r - sqrt(3)/100, num2str(VTick(i)), ...'HorizontalAlignment','left', 'Rotation',-60, fontProp{:})end
end% 繪制小提琴圖
maxf = 0;
for i = 1:size(Data, 2)if iscell(VData)tY = VData{i};elsetY = VData(:,i);endtY(isnan(tY)) = [];[f, yi] = ksdensity(tY);maxf = max(maxf, max(f));
end
for i = 1:size(Data, 2)if iscell(VData)tY = VData{i};elsetY = VData(:,i);endtY(isnan(tY)) = [];[f, yi] = ksdensity(tY);yyi = [min(tY), yi(yi<max(tY) & yi>min(tY)), max(tY)];ind1 = find(yi<max(tY) & yi>min(tY), 1, 'first');ind2 = find(yi<max(tY) & yi>min(tY), 1, 'last');f1 = interp1(yi((ind1 - 1):ind1), f((ind1 - 1):ind1), min(tY));f2 = interp1(yi(ind2:(ind2 + 1)), f(ind2:(ind2 + 1)), max(tY));ff = [f1, f(yi<max(tY) & yi>min(tY)), f2];xx = [ff, -ff(end:-1:1)]./maxf.*(4*pi/5/size(Data, 2)).*width./2;yy = ([yyi, yyi(end:-1:1)] - VLim(1))./diff(VLim).*3./5 + 6/5 + 1/10;xy = [cos(tt(i) - pi/2), - sin(tt(i) - pi/2);sin(tt(i) - pi/2), cos(tt(i) - pi/2)]*[xx; yy];% 繪制小提琴fill(ax, xy(1,:), xy(2,:), mean(tY), 'EdgeColor',[0,0,0], 'LineWidth',1)qt25 = quantile(tY, 0.25);qt75 = quantile(tY, 0.75);med = median(tY);ind3 = find(yi < qt25, 1, 'last');ind4 = find(yi < qt75, 1, 'last');ind5 = find(yi < med, 1, 'last');f3 = interp1(yi(ind3:(ind3 + 1)), f(ind3:(ind3 + 1)), qt25);f4 = interp1(yi(ind4:(ind4 + 1)), f(ind4:(ind4 + 1)), qt75);f5 = interp1(yi(ind5:(ind5 + 1)), f(ind5:(ind5 + 1)), med);xx = [f3, -f3, f4, -f4, f5, -f5]./maxf.*(4*pi/5/size(Data, 2)).*width./2;yy = ([qt25, qt25, qt75, qt75, med, med] - VLim(1))./diff(VLim).*3./5 + 6/5 + 1/10;xy = [cos(tt(i) - pi/2), - sin(tt(i) - pi/2);sin(tt(i) - pi/2), cos(tt(i) - pi/2)]*[xx; yy];% 繪制四分位線和中位線plot(ax, xy(1,1:2), xy(2,1:2), 'LineWidth',1, 'Color','k')plot(ax, xy(1,3:4), xy(2,3:4), 'LineWidth',1, 'Color','k')plot(ax, xy(1,5:6), xy(2,5:6), 'LineWidth',2, 'Color','k')
end% 繪制熱圖
TT = linspace(5*pi/6, pi/6, size(Data, 2) + 1);
for i = 1:size(Data, 1)for j = 1:size(Data, 2)tt = linspace(TT(j), TT(j + 1), 30);r1 = 2/5 + (i - 1)*4/size(Data, 1)/5;r2 = 2/5 + i*4/size(Data, 1)/5;xx = [cos(tt).*r1, cos(tt(end:-1:1)).*r2];yy = [sin(tt).*r1, sin(tt(end:-1:1)).*r2];fill(ax, xx, yy, Data(i,j), 'EdgeColor','w', 'LineWidth',1)end
end% 繪制最上方弧線
tt = linspace(5*pi/6, pi/6, 80);
xx = cos(tt).*2;
yy = sin(tt).*2;
plot(ax, xx(:), yy(:), 'LineWidth',1, 'Color','k')colorbar(ax, 'Position',[.5-.01,.1,.02,.2], fontProp{:});

以上即為完整代碼,數據和完整代碼已經放在以下gitee倉庫:

  • https://gitee.com/slandarer/PLTreprint

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/90149.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/90149.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/90149.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

批量PDF轉換工具,一鍵轉換Word Excel

軟件介紹 今天為大家推薦一款高效的Office文檔批量轉換工具&#xff0c;能夠快速將Word和Excel文件批量轉換為PDF格式。 軟件特點 這款名為"五五Excel word批量轉PDF"的工具體積小巧&#xff0c;不到2M大小&#xff0c;卻能實現強大的批量轉換功能&#xff0c…

面試150 基本計算器

思路 利用棧&#xff08;stack&#xff09;來保存進入括號前的計算狀態&#xff08;包括當前計算結果和符號&#xff09;&#xff0c;以便在括號結束后正確恢復計算上下文。代碼通過遍歷字符串&#xff0c;識別數字、加號、減號和括號。遇到數字時構造完整數值&#xff1b;遇到…

源哈希(sh)解析

源哈希&#xff08;Source Hashing&#xff09;是一種負載均衡算法&#xff0c;它根據請求的源 IP 地址&#xff08;或其他標識符&#xff09;生成哈希值&#xff0c;然后根據這個哈希值將請求分配到特定的后端服務實例。這種方法常用于確保來自同一客戶端的請求始終被路由到同…

axios的使用以及封裝

前言&#xff1a; 在現代前端開發中&#xff0c;網絡請求是不可避免的核心功能之一。無論是獲取后端數據、提交表單信息&#xff0c;還是與第三方 API 交互&#xff0c;高效且可靠的 HTTP 請求庫至關重要。axios 作為一款基于 Promise 的 HTTP 客戶端&#xff0c;憑借其簡潔的 …

github上部署自己的靜態項目

前置知識1、要在github部署項目要提交打包后的靜態文件(html,css&#xff0c;js)到倉庫里2、我們看下github所提供給我們的部署方式有啥&#xff0c;如下所見&#xff1b;要么是/root文件夾&#xff08;就說倉庫里全是打包后的產物&#xff1a;html,css&#xff0c;js要全部放到…

能源管理綜合平臺——分布式能源項目一站式監控

綜合性的能源企業管理面臨著項目多、分布散、信息孤島等問題&#xff0c;分布式的多項目能源在線監控管理平臺是一種集成了多個能源項目的數據采集、監控、分析和管理的系統。平臺集成GIS能力&#xff0c;能夠展示項目的整體分布態勢&#xff0c;對不同地點、不同類型的能源項目…

修改阿里云vps為自定義用戶登錄

win系統上找到控制面板-->用戶賬戶-->更改賬戶類型點擊更改賬戶類型&#xff0c;此時我們看到vps的默認管理員賬戶Administrator。為了防止vps被別人使用默認賬戶Administrator攻擊&#xff0c;我們添加一個用戶賬戶&#xff0c;點擊添加用戶賬戶。 用戶名建議奇葩點&…

Linux: perf: debug問題一例,cpu使用率上升大約2%;多線程如何細化cpu及perf數據分析

文章目錄 前提面臨的問題內核級別函數的差別繼續debug總結根據pid前提 一個進程安置在一個CPU上,新功能上線之后,固定量的業務打起來,占用的CPU是42%。之前沒有新功能的情況下,CPU占用是40%。差了大約2%。而且這個進程里的線程數非常多,有50多個線程。從差距看變化不大,…

計算階梯電費

實現一個 Python 程序&#xff0c;根據使用的電量&#xff08;從控制臺中讓用戶輸入&#xff09;計算需要交的電費&#xff0c;電量分為兩個階梯&#xff0c;小于 200 度和大于 200 度&#xff0c;如果電量小于等于 200 度&#xff0c;電價就是 0.5 元/度&#xff0c;如果電量大…

替代MT6701,3D 霍爾磁性角度傳感器芯片

KTH5502 是一款基于垂直霍爾技術的高精度絕對角度傳感器芯片&#xff0c;支持全角度&#xff08;0–360&#xff09;測量。 芯片內部集成 X、Y 軸的垂直霍爾元件和 Z 軸的水平霍爾元件&#xff0c;能夠同時感知磁場在 X、Y、Z 三個 方向的變化。得益于垂直霍爾技術優異的正交匹…

華為 Mate 80 影像配置揭秘:硬軟雙升

7 月 7 日&#xff0c;知名數碼博主爆料了華為 Mate 80 系列的影像配置&#xff0c;引發廣泛關注。從曝光信息來看&#xff0c;Mate 80 系列在影像方面延續華為的技術探索&#xff0c;通過硬件升級與算法優化&#xff0c;力圖為用戶帶來更出色的拍攝體驗。? 爆料顯示&#xff…

Android studio升級AGP需要注意哪些

deep seek回答&#xff1a; 深度思考完成 用時26秒 嗯&#xff0c;用戶詢問的是在Android Studio中升級AGP需要注意哪些事項。這個問題很實用&#xff0c;因為AGP升級確實是個容易踩坑的過程。讓我看看搜索結果里有什么關鍵信息。 首先注意到搜索結果里有幾個高可信度的資料專…

MapReduce數據處理過程2萬字保姆級教程

目錄 1. MapReduce 的核心思想:分而治之的藝術 2. Hadoop MapReduce 的架構:從宏觀到微觀 3. WordCount 實例:從代碼到執行的完整旅程 4. 源碼剖析:Job.submit 的魔法 5. Map 任務的執行:從分片到鍵值對 6. Shuffle 階段:MapReduce 的幕后英雄 7. Reduce 任務的執行…

Rust單例模式:OnceLock的使用指南

想象一下你在構建一個需要全局數據庫連接的Rust應用。傳統語言里&#xff0c;單例模式常常伴隨著鎖的沉重和初始化競態的焦慮。但在Rust的世界里&#xff0c;OnceLock就像個輕巧的守門人&#xff0c;只允許一次安全的通行。 簡潔的OnceLock實現 看看這段代碼如何優雅地解決單…

JavaScript性能優化實戰:表格控件高效開發指南

引言 在現代Web應用開發中&#xff0c;電子表格功能已成為數據分析、報表展示等場景的核心需求。SpreadJS作為一款高性能的純前端電子表格控件&#xff0c;能夠完美兼容Excel文件格式&#xff0c;支持百萬級數據量和復雜公式計算。然而隨著數據規模的增長和業務邏輯的復雜化&a…

RWA(現實世界資產)代幣化系統構建指南:合規、跨境與機構級解決方案

——金融科技公司機構市場拓展戰略報告前言&#xff1a;RWA代幣化的機構化浪潮與市場機遇 截至2025年6月&#xff0c;全球RWA&#xff08;Real World Assets&#xff09;鏈上規模突破240億美元&#xff0c;3年增長超380%&#xff0c;成為僅次于穩定幣的增速第二賽道。貝萊德、摩…

QML Label組件

QML中的Label組件是構建用戶界面時最常用的文本顯示控件之一&#xff0c;它繼承自Text元素但提供了更豐富的UI特性和主題集成支持。本文將全面介紹Label的核心功能、屬性配置、使用技巧以及與Text組件的區別&#xff0c;幫助開發者高效構建美觀的文本界面。 Label組件基礎 La…

使用 GDB 調試 Redis 服務進程指南

1. 準備工作 安裝 GDB 在大多數 Linux 發行版上&#xff0c;執行&#xff1a; sudo apt-get update sudo apt-get install gdb確保有足夠磁盤空間 Core dump 文件可能較大&#xff0c;請提前檢查磁盤剩余空間&#xff1a; df -h .可選&#xff1a;使用 tmux 或 screen 為避免 S…

深度學習-環境準備

安裝python&#xff0c;miniconda(最后步驟關于python環境變量部分全部勾選)&#xff0c;pycharm 關于離線安裝numpy和matplotlib&#xff08;我的環境連不上網&#xff09; 我們先去 PyPI The Python Package Index 下載離線包 在搜索框搜索你的包名稱&#xff0c;這里是 m…

記錄在Windows系統用Python 3.12環境實現Nuitka過程

內容只提供Windows 10 與 Windows 11 下&#xff0c;搭建 Python 3.12 環境&#xff0c;并使用 Nuitka 將腳本打包為可執行文件的詳細流程。全文分為以下幾部分&#xff1a; 準備工作與系統要求 安裝 Python 3.12 配置環境變量與 pip 創建虛擬環境&#xff08;推薦&#xff…