一、引言:当数据分布拥有「层次感」—— 山脊图的魅力​

在数据可视化的世界里,我们常常需要同时展示多个分布的形态差异。传统的重叠密度图虽然能呈现整体趋势,但当分布数量较多时,曲线交叠会让画面变得杂乱。这时候,山脊图(Ridgeline Plot)就像一位优雅的舞者,用层次分明的「数据山脉」展现每个分布的独特轮廓,让复杂数据瞬间变得清晰易懂。​

今天,我们将通过一段完整的 MATLAB 代码,带大家从零开始实现一个精美的山脊图。不仅会详细解析每一行代码的作用,还会告诉你如何替换成自己的数据,甚至玩转可视化细节优化。准备好了吗?让我们一起走进这场「数据山脉」的绘制之旅吧!🌄​

二、代码全景:先睹为快的完整实现​

在正式解析前,先放上完整的 MATLAB 代码,方便大家有一个整体认知:

% 生成山脊图数据并绘图
rng(42); % 设置随机种子保证可重复性% 参数设置
numSamples = 10;   % 样本数 (A-J)
numPoints = 500;   % 每个样本的数据点数
x = linspace(0, 90, numPoints); % X轴范围0-90
yOffset = 1.5;     % 样本间的垂直间距% 生成随机均值和标准差 (控制分布位置和宽度)
mus = linspace(20, 70, numSamples);
sigmas = linspace(4, 12, numSamples) .* rand(1, numSamples);% 预计算核密度并绘图
figure('Color', 'white');
hold on;% 颜色映射 (从蓝到红)
colors = parula(numSamples);for i = numSamples:-1:1  % 倒序绘制确保标签位置正确% 生成正态分布随机数据data = mus(i) + sigmas(i) * randn(numPoints, 1);% 计算核密度估计[f, xi] = ksdensity(data, x, 'Bandwidth', 3);f_normalized = f / max(f) * 0.8; % 归一化高度% 计算当前样本的基线baseline = (numSamples - i) * yOffset;% 绘制填充区域fill([xi, fliplr(xi)], ...[baseline + f_normalized, fliplr(baseline*ones(1, numPoints))], ...colors(i, :), ...'FaceAlpha', 0.7, ...'EdgeColor', 'none');% 添加样本标签text(5, baseline + 0.3, ['Sample ', char('A' + numSamples - i)], ...'FontWeight', 'bold', ...'FontSize', 10);
end% 美化图形
set(gca, 'YTick', [], 'YColor', 'none'); % 隐藏Y轴
xlabel('K (w)');
title('Ridgeline Plot', 'FontSize', 14);
grid on;
box on;
xlim([0, 90]);
ylim([0, yOffset*numSamples + 0.5]);
hold off;

运行这段代码,你会得到一个包含 10 个样本分布的山脊图,每个「山脊」代表一个样本的密度分布,垂直排列的设计让每个分布的位置、宽度和峰值一目了然。接下来,我们逐行拆解其中的关键逻辑。​

三、核心代码解析:数据生成与可视化的「山脉构造」​

1. 随机种子设置:让结果可复现的「魔法咒语」

rng(42); % 设置随机种子保证可重复性
  • 作用:rng函数用于设置随机数生成器的种子,这里使用42作为种子(一个在编程界充满神秘色彩的数字😉)。设置后,每次运行代码生成的随机数序列都相同,确保结果可复现,这对学术研究或协作场景非常重要。​
  • 可替换点:如果不需要固定随机结果,直接删除这行即可;若想换一个固定结果,修改括号内的数字(如rng(123))。​

2. 参数设置:定义「山脉」的基本框架

numSamples = 10;   % 样本数 (A-J)
numPoints = 500;   % 每个样本的数据点数
x = linspace(0, 90, numSamples); % X轴范围0-90
yOffset = 1.5;     % 样本间的垂直间距
  • numSamples:控制样本数量,代码中生成了 A-J 共 10 个样本,对应 10 个「山脊」。如果你有 20 个样本,这里就设为 20。​
  • numPoints:每个样本生成的数据点数,数值越大,密度曲线越平滑(但计算量也会增加),通常 500-1000 是不错的选择。​
  • x:定义 X 轴的范围和采样点,这里用linspace(0, 90, 500)生成从 0 到 90 均匀分布的 500 个点,作为密度估计的横轴坐标。​
  • yOffset:控制每个样本在 Y 轴方向的间距,数值越大,「山脊」之间的间隔越宽,避免重叠过多;数值越小,画面更紧凑。​

3. 分布参数生成:赋予每个「山脊」独特形态

mus = linspace(20, 70, numSamples);
sigmas = linspace(4, 12, numSamples) .* rand(1, numSamples);
  • 均值mus:使用linspace生成从 20 到 70 的等差数列,作为每个样本正态分布的均值。这样样本的中心位置会从左到右逐渐移动,形成明显的位置差异。​
  • 标准差sigmas:基础范围是 4 到 12,再乘以一个随机数(rand(1, numSamples)生成 0-1 之间的随机数),让每个样本的分布宽度既有规律又有变化。这样有的「山脊」瘦高(标准差小),有的矮胖(标准差大),模拟真实数据的多样性。​

4. 图形初始化与颜色映射:搭建画布与调色盘

figure('Color', 'white'); % 创建白色背景的画布
hold on; % 保持图形,允许后续添加元素
colors = parula(numSamples); % 生成与样本数匹配的颜色映射(Parula色阶,MATLAB默认的优秀色阶)
  • 画布设置:figure('Color', 'white')创建一个白色背景的图形窗口,避免默认灰色背景干扰数据展示。​
  • 颜色映射:parula是 MATLAB 推荐的感知均匀色阶,适合连续数据可视化。numSamples决定颜色数量,每个样本对应一种颜色,这里从蓝到红渐变,视觉上容易区分。​

5. 循环绘制:逐个构建「山脊」的核心逻辑

for i = numSamples:-1:1  % 倒序绘制确保标签位置正确

这里使用倒序循环(从 10 到 1),是因为后续绘制时,底层的「山脊」会被上层覆盖,倒序可以先画底层样本,再画上层,避免标签被遮挡(后面会详细解释标签位置)。​

5.1 生成正态分布数据

data = mus(i) + sigmas(i) * randn(numPoints, 1);
  • 利用正态分布公式均值 + 标准差×随机数生成数据,randn生成服从标准正态分布的随机数,numPoints, 1表示生成 500 行 1 列的列向量。​

5.2 核密度估计:让离散数据「平滑成山」

[f, xi] = ksdensity(data, x, 'Bandwidth', 3);
  • ksdensity函数:用于计算核密度估计(Kernel Density Estimation, KDE),将离散数据转换为连续的密度曲线。​
  • data:输入的样本数据(列向量)。​
  • x:指定计算密度的横轴坐标(即前面定义的 0-90 的 500 个点)。​
  • 'Bandwidth':带宽参数,控制曲线平滑度。数值越大,曲线越平滑;越小,越贴近原始数据波动。这里设为 3,是一个平衡值。​
  • 输出f是密度估计值,xi是对应的横轴坐标(与x相同,这里主要是为了代码一致性)。​

5.3 归一化处理:控制「山脊」高度

f_normalized = f / max(f) * 0.8; % 归一化高度
  • 为什么归一化?直接使用密度值绘制会导致不同样本的「山脊」高度差异过大(因为密度值与数据范围相关),归一化后将每个样本的密度峰值缩放到 0.8 倍的相对高度,让所有「山脊」在视觉上高度统一,便于比较形状而非绝对密度。​

5.4 基线计算:确定「山脊」的垂直位置

baseline = (numSamples - i) * yOffset;
  • 第一个样本(i=10)的基线是(10-10)*1.5=0,第二个(i=9)是(10-9)*1.5=1.5,依此类推,最后一个样本(i=1)是(10-1)*1.5=13.5。这样每个样本从上到下依次排列,间距为 1.5。​

5.5 绘制填充区域:用颜色填充「山体」

fill([xi, fliplr(xi)], ...[baseline + f_normalized, fliplr(baseline*ones(1, numPoints))], ...colors(i, :), ...'FaceAlpha', 0.7, ...'EdgeColor', 'none');
  • 填充原理:fill函数通过指定顶点坐标绘制多边形。这里将密度曲线的点(xi, baseline + f_normalized)与基线的反向点(fliplr(xi), baseline)连接,形成一个闭合区域(类似梯形 + 曲线的形状)。​
  • fliplr(xi):将 xi 反转,用于闭合路径的底部横轴。​
  • baseline*ones(1, numPoints):生成与 xi 等长的基线向量,反转后作为底部 Y 坐标,形成从曲线到基线的闭合区域。​
  • 视觉参数:​
  • FaceAlpha=0.7:设置填充颜色透明度,避免完全不透明导致下层「山脊」被遮挡。​
  • EdgeColor='none':不绘制边框,让图形更简洁。​

5.6 添加样本标签:给每座「山」命名

text(5, baseline + 0.3, ['Sample ', char('A' + numSamples - i)], ...'FontWeight', 'bold', ...'FontSize', 10);
  • 标签逻辑:利用倒序循环,当 i=10 时,numSamples - i=0,标签为 'A';i=9 时,numSamples - i=1,标签为 'B',依此类推,最终生成 A-J 的标签。​
  • 位置设置:X 坐标固定为 5(位于画布左侧),Y 坐标为基线 + 0.3,确保标签显示在对应「山脊」的左侧空白处,不与图形重叠。​

四、用户数据替换指南:让代码适配你的场景​

现在重点来了!如果你想将这段代码用于自己的数据,需要修改哪些部分呢?以下是详细的替换指南:​

1. 替换原始数据:从随机生成到真实输入​

当前代码使用正态分布随机数据,如果你有真实数据,步骤如下:​

场景一:已知每个样本的原始数据​

  • 数据格式:假设你有 10 个样本,每个样本的数据存储为单元格数组data_samples,其中data_samples{1}是样本 A 的数据,data_samples{2}是样本 B 的数据,依此类推。​
  • 修改代码:​
  • 删除mus和sigmas的生成代码。​
  • 在循环中,将data = mus(i) + sigmas(i) * randn(...)替换为data = data_samples{i};。​
  • 确保每个样本的数据点数可以不同(但ksdensity会自动处理,无需统一长度)。​

场景二:已知每个样本的均值和标准差​

  • 如果你只有均值和标准差(比如通过统计得到),直接替换mus和sigmas为你的数据:
mus = [25, 30, 35, 40, 45, 50, 55, 60, 65, 70]; % 自定义均值
sigmas = [5, 6, 7, 8, 9, 10, 9, 8, 7, 6]; % 自定义标准差

2. 修改 X 轴范围和标签​

  • 当前 X 轴标签是 'K (w)',如果你是其他数据(如温度、时间、分数),直接修改xlabel内容:
xlabel('温度 (℃)'); % 示例:温度数据

X 轴范围x = linspace(0, 90, numPoints)可根据数据实际范围调整,比如数据在 10-80 之间,改为: 

x = linspace(10, 80, 500);

3. 调整样本数量和间距​

  • 增加 / 减少样本数:修改numSamples,比如设为 15,同时确保你的数据有 15 个样本。​
  • 调整垂直间距:修改yOffset,数值越大,「山脊」之间越稀疏(建议 0.5-2 之间调整,根据样本数量选择:样本多则间距小,样本少可适当增大)。​

4. 自定义颜色和标签​

  • 颜色映射:默认使用parula色阶,可替换为其他色阶(如jet、hot、cool),或自定义颜色矩阵:
colors = [0 0 1; 0 0.5 1; 0 1 1; ...]; % 自定义RGB颜色,每行一个颜色

标签内容:当前标签是 'Sample A-J',可替换为自定义标签,比如样本名称数组: 

labels = {'Group 1', 'Group 2', 'Group 3', ..., 'Group 10'}; % 定义标签数组
text(5, baseline + 0.3, labels{numSamples - i + 1}, ...); % 注意索引顺序

五、细节优化:让图形更专业美观​

1. 坐标轴与网格设置

set(gca, 'YTick', [], 'YColor', 'none'); % 隐藏Y轴
grid on; % 显示网格线
box on; % 显示图形边框
xlim([0, 90]); % 固定X轴范围
ylim([0, yOffset*numSamples + 0.5]); % 自动计算Y轴范围
  • 隐藏 Y 轴:山脊图的 Y 轴通常不代表实际数据,只是垂直间距,所以隐藏 Y 轴刻度和标签,让焦点集中在 X 轴和分布形态上。​
  • 网格与边框:网格线帮助观察 X 轴数值,边框让图形更规整。​

2. 标题与字体设置

title('Ridgeline Plot', 'FontSize', 14); % 主标题
% 可添加副标题:
text(0.5, 1.05, '多个样本分布对比', 'FontSize', 12, 'FontWeight', 'bold', 'HorizontalAlignment', 'center', 'Units', 'normalized');
  • 使用text函数添加副标题,Units', 'normalized'让位置基于画布比例(0-1),HorizontalAlignment' 'center'使文字居中。​

3. 透明度与边缘处理

'FaceAlpha', 0.7, % 填充透明度
'EdgeColor', 'none', % 无边缘线
  • 透明度设置让下层「山脊」的轮廓隐约可见,增加层次感;去除边缘线避免画面杂乱。​

六、应用场景:山脊图的「用武之地」​

山脊图因其独特的可视化效果,在多个领域都有出色表现:​

  • 生物学:展示不同物种的体长、体重分布差异。​
  • 市场调研:对比不同地区的消费者年龄、消费金额分布。​
  • 气象学:呈现不同月份的温度、降水量分布变化。​
  • 教育学:分析不同班级的成绩分布形态(是否偏科、两极分化等)。​
  • 金融学:可视化不同资产的收益率分布,识别风险差异。​

举个例子:如果你是电商分析师,想对比 12 个月的用户购买金额分布,就可以用山脊图展示每个月的分布曲线,一眼看出哪些月份的购买金额均值更高、波动更大。​

七、常见问题与解决方案​

1. 「山脊」重叠过多怎么办?​

  • 原因:yOffset太小或f_normalized的归一化系数太大(当前是 0.8,可减小到 0.6)。​
  • 解决:增大yOffset(如从 1.5 改为 2),或减小归一化系数(如*0.6),降低「山脊」高度。​

2. 标签被图形遮挡怎么办?​

  • 原因:倒序循环时,标签位置计算错误,或baseline + 0.3的偏移量不够。​
  • 解决:确保循环是倒序(numSamples:-1:1),并适当调整标签的 Y 坐标(如baseline + 0.5)。​

3. 颜色不够区分怎么办?​

  • 解决:使用colororder(colors)调整颜色顺序,或换用对比度更高的色阶(如lines色阶,但更适合少量样本)。​

八、总结:动手打造你的专属数据山脉​

通过今天的分享,我们不仅掌握了山脊图的核心绘制逻辑,还学会了如何替换真实数据、调整可视化细节。从随机数据生成到核密度估计,从颜色映射到标签添加,每一步都是为了让数据分布以最清晰、美观的方式呈现。​

现在,轮到你动手实践啦!💻 打开 MATLAB,替换成你的数据,调整参数,看看属于你的「数据山脉」如何崛起。记得在遇到问题时回顾本文的「用户数据替换指南」和「常见问题」,相信你一定能绘制出令人惊叹的山脊图!​

如果觉得本文有用,欢迎分享给身边的数据分析小伙伴。下次我们将探讨更多高级可视化技巧,记得关注哦~ 祝你绘图愉快,数据可视化之路越走越顺!🚀

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/bicheng/85590.shtml
繁体地址,请注明出处:http://hk.pswp.cn/bicheng/85590.shtml
英文地址,请注明出处:http://en.pswp.cn/bicheng/85590.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

跨境电商每周资讯—6.16-6.20

1. Instagram 在亚太地区逐渐超越 TikTok 在整个亚太地区,Instagram用户数量正逐渐超过TikTok。预计2025年日本Instagram用户数量将增至4440万,印度今年用户数量将增长10%,领跑亚太。与之形成对比的是,TikTok在一些国家增长速度放…

计算机网络 网络层:数据平面(一)

前一节学习了运输层依赖于网络层的主机到主机的通信服务,提供各种形式的进程到进程的通信。了解这种主机到主机通信服务的真实情况,是什么使得它工作起来的。 在本章和下一章,将学习网络层实际是怎样实现主机到主机的通信服务。与运输层和应用…

Suna本地部署详细教程

一、安装基础环境 # 1、创建环境 conda create -n suna python3.11.7# 2、激活虚拟环境 conda activate suna# 3、安装jupyter和ipykernel pip install jupyter ipykernel# 4、将虚拟环境添加到jupyter # python -m ipykernel install --user --namemyenv --display-name"…

LeetCode 每日一题打卡|若谷的刷题日记 3day--最长连续序列

1.最长连续序列 题目: 给定一个未排序的整数数组 nums ,找出数字连续的最长序列(不要求序列元素在原数组中连续)的长度。 请你设计并实现时间复杂度为 O(n) 的算法解决此问题。 示例 1: 输入:nums [1…

EfficientVLA:面向视觉-语言-动作模型无训练的加速与压缩

25年6月来自上海交大、哈工大、西安交大和电子科大(成都)的论文“EfficientVLA: Training-Free Acceleration and Compression for Vision-Language-Action Models”。 视觉-语言-动作 (VLA) 模型,特别是基于扩散的架构,展现出具…

wireshark抓包分析TCP数据包

1、直接从TCP的三次握手开始说起 三次握手就是客户与服务器建立连接的过程 客户向服务器发送SYN(SEQ=x)报文,然后就会进入SYN_SEND状态服务器收到SYN报文之后,回应一个SYN(SEQ=y)ACK(ACK=x+1)报文,然后就会进入SYN_RECV状态客户收到服务器的SYN报文,回应一个ACK(AC…

同等学力申硕-计算机统考-历年真题和备考经验

同等学力申请硕士学位考试是比较适合在职人员的提升学位方式,了解过的人应该都知道,现在社会的竞争压力越来越大,为了提高职业生存能力,提升学位在所难免。 一、已有计算机统考历年真题资料 报名过同等学力申硕计算机专业的朋友都…

OSI网络通信模型详解

OSI 模型就是把这整个过程拆解成了 7 个明确分工的步骤,每一层只负责自己那一摊事儿,这样整个系统才能顺畅运转,出了问题也容易找到“锅”在谁那。 核心比喻:寄快递 📦 想象你要把一份重要的礼物(你的数据…

C++ 检测文件大小和文件传输

检测文件的大小 你可以通过标准 C/C 的文件 API 很方便地获取文件的字节大小&#xff0c;以下是几种常用方法&#xff1a; ✅ 方法一&#xff1a;使用 stat() 函数&#xff08;推荐&#xff09; #include <sys/stat.h> #include <stdio.h>off_t get_file_size(co…

Ubuntu 中修改网卡 IP

在 Ubuntu 中修改网卡 IP 地址可以通过以下方法实现&#xff0c;具体取决于你使用的网络管理工具&#xff08;如 netplan、ifconfig/ip 命令或传统 interfaces 文件&#xff09;。以下是常见方法&#xff1a; 方法 1&#xff1a;使用 netplan&#xff08;Ubuntu 17.10 及更新版…

记录学习three.js 为什么 .glTF 是更适合 Web 的 3D 模型格式?——从 .OBJ 到 .glTF 的转变⑭

在上一篇中&#xff0c;我们介绍了如何在 Three.js 中加载 .OBJ 模型。如果你没看过&#xff0c;建议先阅读一下基础内容。然而你很快会发现&#xff0c;.OBJ 虽然入门简单&#xff0c;却并不是 Web3D 场景中的最佳格式。 .OBJ 是什么&#xff1f; .OBJ 是最早期的3D交换格式之…

H递归函数.go

前言&#xff1a;递归函数是一种强大而又充满魅力的编程技巧。它就像是一面神奇的镜子&#xff0c;函数在其中能够调用自身的倒影&#xff0c;从而以一种简洁而优雅的方式解决许多复杂的问题。 目录 一、递归函数是啥玩意儿 二、递归函数的优缺点 优点 缺点 三、递归函数…

软件功能测试的测试标准

一、软件功能测试行业标准概述 软件功能测试行业标准是规范软件测试流程、方法、工具及人员资质的准则&#xff0c;是确保软件产品的功能性、可靠性、易用性等质量特性符合用户需求。这些标准不仅为测试人员提供了明确的指导&#xff0c;也为软件产品的质量控制提供了有力保障。…

EchoEar(喵伴):乐鑫发布与火山引擎扣子联名 AI 智能体开发板

随着生成式人工智能技术的快速发展&#xff0c;大语言模型 (LLM) 正逐步成为推动智能设备升级的核心力量。乐鑫科技携手火山引擎扣子大模型团队&#xff0c;共同推出智能 AI 开发套件 —— EchoEar&#xff08;喵伴&#xff09;。该套件以端到端开发为核心理念&#xff0c;构建…

图像特征检测算法SIFT

SIFT&#xff08;Scale - Invariant Feature Transform&#xff0c;尺度不变特征变换&#xff09;是一种计算机视觉领域的特征提取算法&#xff0c;具有重要的地位和广泛的应用。 算法原理 构建高斯金字塔 &#xff1a; 为了实现多尺度检测&#xff0c;SIFT 算法会构建高斯金…

光纤通道收发器:市场洞察、技术演进与未来机遇

一、引言 在数字化浪潮席卷全球的当下&#xff0c;数据存储与传输的需求呈爆发式增长。光纤通道收发器作为高速、可靠数据存储网络&#xff08;如存储区域网络 SAN&#xff09;中的关键组件&#xff0c;发挥着至关重要的作用。它通过光纤实现服务器、存储设备和交换机之间的数…

candence17.4如何设置两个焊盘之间在TOP与BOTTOM可以存在两根线

为什么要走两根线&#xff1f; 为了过大电流&#xff0c;有时候就需要我们在TOP、BOTTOM两个面走线&#xff0c;同时开窗&#xff0c;然后通过加锡的方式增加过流能力&#xff1b; 当然由于两面都有导线&#xff0c;必然会存在过孔&#xff0c;而过孔的过流能力不仅与过孔孔径…

Dify:参数调节,让LLM从能用到好用的机制

前言 随着大语言模型(LLM)在文本生成、智能对话、技术问答等前沿领域的深度渗透&#xff0c;参数精细化调节已成为开发者驾驭 AI 能力的核心必修课。 本文将系统的解释温度(Temperature)、核采样(Top - P)、截断采样(Top - K)等关键参数的底层作用机制&#xff0c;结合多种场景…

防抖不同的实现

防抖&#xff08;Debounce&#xff09;&#xff1a;在事件被触发后&#xff0c;延迟一段时间再执行函数。如果在延迟期间事件再次被触发&#xff0c;则重新计时。常用于搜索框输入、窗口大小调整等场景。 1.不安装任何依赖和库&#xff0c;编写一个防抖的函数 在utils里面增加…

MySQL 数据库索引详解

一、索引是什么&#xff1f;能干嘛&#xff1f; 类比理解&#xff1a;索引就像书的目录。比如你想查《哈利波特》中 “伏地魔” 出现的页数&#xff0c;不用逐页翻书&#xff0c;直接看目录找关键词就行。数据库里的索引就是帮你快速找到数据的 “目录”。 核心作用&#xff…